summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/aliases.nim28
-rw-r--r--compiler/ast.nim89
-rw-r--r--compiler/astalgo.nim194
-rw-r--r--compiler/bitsets.nim12
-rw-r--r--compiler/btrees.nim14
-rw-r--r--compiler/canonicalizer.nim86
-rw-r--r--compiler/ccgcalls.nim254
-rw-r--r--compiler/ccgexprs.nim598
-rw-r--r--compiler/ccgliterals.nim18
-rw-r--r--compiler/ccgmerge.nim12
-rw-r--r--compiler/ccgstmts.nim339
-rw-r--r--compiler/ccgthreadvars.nim18
-rw-r--r--compiler/ccgtrav.nim36
-rw-r--r--compiler/ccgtypes.nim379
-rw-r--r--compiler/ccgutils.nim16
-rw-r--r--compiler/cgen.nim371
-rw-r--r--compiler/cgendata.nim2
-rw-r--r--compiler/cgmeth.nim128
-rw-r--r--compiler/closureiters.nim64
-rw-r--r--compiler/commands.nim22
-rw-r--r--compiler/depends.nim10
-rw-r--r--compiler/dfa.nim87
-rw-r--r--compiler/docgen.nim225
-rw-r--r--compiler/enumtostr.nim30
-rw-r--r--compiler/evalffi.nim112
-rw-r--r--compiler/evaltempl.nim36
-rw-r--r--compiler/extccomp.nim78
-rw-r--r--compiler/filter_tmpl.nim2
-rw-r--r--compiler/filters.nim16
-rw-r--r--compiler/forloops.nim4
-rw-r--r--compiler/guards.nim344
-rw-r--r--compiler/hlo.nim16
-rw-r--r--compiler/idents.nim8
-rw-r--r--compiler/importer.nim52
-rw-r--r--compiler/injectdestructors.nim4
-rw-r--r--compiler/int128.nim14
-rw-r--r--compiler/jsgen.nim608
-rw-r--r--compiler/jstypes.nim94
-rw-r--r--compiler/lambdalifting.nim81
-rw-r--r--compiler/layouter.nim4
-rw-r--r--compiler/lexer.nim67
-rw-r--r--compiler/liftdestructors.nim71
-rw-r--r--compiler/liftlocals.nim10
-rw-r--r--compiler/linter.nim5
-rw-r--r--compiler/llstream.nim24
-rw-r--r--compiler/lookups.nim64
-rw-r--r--compiler/lowerings.nim152
-rw-r--r--compiler/magicsys.nim4
-rw-r--r--compiler/modulepaths.nim4
-rw-r--r--compiler/modules.nim4
-rw-r--r--compiler/msgs.nim21
-rw-r--r--compiler/nimblecmd.nim4
-rw-r--r--compiler/nimconf.nim26
-rw-r--r--compiler/nimlexbase.nim2
-rw-r--r--compiler/nimsets.nim60
-rw-r--r--compiler/options.nim10
-rw-r--r--compiler/parampatterns.nim48
-rw-r--r--compiler/parser.nim381
-rw-r--r--compiler/passes.nim14
-rw-r--r--compiler/patterns.nim119
-rw-r--r--compiler/platform.nim8
-rw-r--r--compiler/plugins/itersgen.nim2
-rw-r--r--compiler/plugins/locals.nim2
-rw-r--r--compiler/pragmas.nim122
-rw-r--r--compiler/prefixmatches.nim7
-rw-r--r--compiler/procfind.nim35
-rw-r--r--compiler/renderer.nim372
-rw-r--r--compiler/reorder.nim30
-rw-r--r--compiler/rodimpl.nim66
-rw-r--r--compiler/rodutils.nim14
-rw-r--r--compiler/ropes.nim36
-rw-r--r--compiler/saturate.nim2
-rw-r--r--compiler/sem.nim35
-rw-r--r--compiler/semcall.nim115
-rw-r--r--compiler/semdata.nim23
-rw-r--r--compiler/semexprs.nim772
-rw-r--r--compiler/semfields.nim54
-rw-r--r--compiler/semfold.nim140
-rw-r--r--compiler/semgnrc.nim228
-rw-r--r--compiler/seminst.nim56
-rw-r--r--compiler/semmacrosanity.nim28
-rw-r--r--compiler/semmagic.nim73
-rw-r--r--compiler/semobjconstr.nim52
-rw-r--r--compiler/semparallel.nim81
-rw-r--r--compiler/sempass2.nim244
-rw-r--r--compiler/semstmts.nim679
-rw-r--r--compiler/semtempl.nim314
-rw-r--r--compiler/semtypes.nim491
-rw-r--r--compiler/semtypinst.nim149
-rw-r--r--compiler/sighashes.nim44
-rw-r--r--compiler/sigmatch.nim419
-rw-r--r--compiler/sizealignoffsetimpl.nim56
-rw-r--r--compiler/spawn.nim46
-rw-r--r--compiler/suggest.nim58
-rw-r--r--compiler/syntaxes.nim20
-rw-r--r--compiler/tccgen.nim2
-rw-r--r--compiler/transf.nim531
-rw-r--r--compiler/trees.nim38
-rw-r--r--compiler/treetab.nim22
-rw-r--r--compiler/types.nim431
-rw-r--r--compiler/typesrenderer.nim34
-rw-r--r--compiler/vm.nim136
-rw-r--r--compiler/vmdef.nim2
-rw-r--r--compiler/vmdeps.nim62
-rw-r--r--compiler/vmgen.nim518
-rw-r--r--compiler/vmmarshal.nim38
-rw-r--r--compiler/vmops.nim4
-rw-r--r--compiler/wordrecg.nim2
-rw-r--r--compiler/writetracking.nim83
109 files changed, 6116 insertions, 6255 deletions
diff --git a/compiler/aliases.nim b/compiler/aliases.nim
index fb2a39bc5..34b81cbad 100644
--- a/compiler/aliases.nim
+++ b/compiler/aliases.nim
@@ -22,17 +22,17 @@ proc isPartOfAux(n: PNode, b: PType, marker: var IntSet): TAnalysisResult =
   result = arNo
   case n.kind
   of nkRecList:
-    for i in 0 ..< len(n):
-      result = isPartOfAux(n.sons[i], b, marker)
+    for i in 0..<n.len:
+      result = isPartOfAux(n[i], b, marker)
       if result == arYes: return
   of nkRecCase:
-    assert(n.sons[0].kind == nkSym)
-    result = isPartOfAux(n.sons[0], b, marker)
+    assert(n[0].kind == nkSym)
+    result = isPartOfAux(n[0], b, marker)
     if result == arYes: return
-    for i in 1 ..< len(n):
-      case n.sons[i].kind
+    for i in 1..<n.len:
+      case n[i].kind
       of nkOfBranch, nkElse:
-        result = isPartOfAux(lastSon(n.sons[i]), b, marker)
+        result = isPartOfAux(lastSon(n[i]), b, marker)
         if result == arYes: return
       else: discard "isPartOfAux(record case branch)"
   of nkSym:
@@ -46,14 +46,14 @@ proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult =
   if compareTypes(a, b, dcEqIgnoreDistinct): return arYes
   case a.kind
   of tyObject:
-    if a.sons[0] != nil:
-      result = isPartOfAux(a.sons[0].skipTypes(skipPtrs), b, marker)
+    if a[0] != nil:
+      result = isPartOfAux(a[0].skipTypes(skipPtrs), b, marker)
     if result == arNo: result = isPartOfAux(a.n, b, marker)
   of tyGenericInst, tyDistinct, tyAlias, tySink:
     result = isPartOfAux(lastSon(a), b, marker)
   of tyArray, tySet, tyTuple:
-    for i in 0 ..< len(a):
-      result = isPartOfAux(a.sons[i], b, marker)
+    for i in 0..<a.len:
+      result = isPartOfAux(a[i], b, marker)
       if result == arYes: return
   else: discard
 
@@ -108,7 +108,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
           result = arMaybe
     of nkBracketExpr:
       result = isPartOf(a[0], b[0])
-      if len(a) >= 2 and len(b) >= 2:
+      if a.len >= 2 and b.len >= 2:
         # array accesses:
         if result == arYes and isDeepConstExpr(a[1]) and isDeepConstExpr(b[1]):
           # we know it's the same array and we have 2 constant indexes;
@@ -181,14 +181,14 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
       else: discard
     of nkObjConstr:
       result = arNo
-      for i in 1 ..< b.len:
+      for i in 1..<b.len:
         let res = isPartOf(a, b[i][1])
         if res != arNo:
           result = res
           if res == arYes: break
     of nkCallKinds:
       result = arNo
-      for i in 1 ..< b.len:
+      for i in 1..<b.len:
         let res = isPartOf(a, b[i])
         if res != arNo:
           result = res
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 723a4a1de..9fbcab144 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -1025,27 +1025,27 @@ type Indexable = PNode | PType
 
 proc len*(n: Indexable): int {.inline.} =
   when defined(nimNoNilSeqs):
-    result = len(n.sons)
+    result = n.sons.len
   else:
     if isNil(n.sons): result = 0
-    else: result = len(n.sons)
+    else: result = n.sons.len
 
 proc safeLen*(n: PNode): int {.inline.} =
   ## works even for leaves.
   if n.kind in {nkNone..nkNilLit}: result = 0
-  else: result = len(n)
+  else: result = n.len
 
 proc safeArrLen*(n: PNode): int {.inline.} =
   ## works for array-like objects (strings passed as openArray in VM).
-  if n.kind in {nkStrLit..nkTripleStrLit}:result = len(n.strVal)
+  if n.kind in {nkStrLit..nkTripleStrLit}:result = n.strVal.len
   elif n.kind in {nkNone..nkFloat128Lit}: result = 0
-  else: result = len(n)
+  else: result = n.len
 
-proc add*(father, son: PNode) =
+proc add*(father, son: Indexable) =
   assert son != nil
   when not defined(nimNoNilSeqs):
     if isNil(father.sons): father.sons = @[]
-  add(father.sons, son)
+  father.sons.add(son)
 
 template `[]`*(n: Indexable, i: int): Indexable = n.sons[i]
 template `[]=`*(n: Indexable, i: int; x: Indexable) = n.sons[i] = x
@@ -1144,18 +1144,18 @@ const                         # for all kind of hash tables:
 
 proc copyStrTable*(dest: var TStrTable, src: TStrTable) =
   dest.counter = src.counter
-  setLen(dest.data, len(src.data))
-  for i in 0 .. high(src.data): dest.data[i] = src.data[i]
+  setLen(dest.data, src.data.len)
+  for i in 0..high(src.data): dest.data[i] = src.data[i]
 
 proc copyIdTable*(dest: var TIdTable, src: TIdTable) =
   dest.counter = src.counter
-  newSeq(dest.data, len(src.data))
-  for i in 0 .. high(src.data): dest.data[i] = src.data[i]
+  newSeq(dest.data, src.data.len)
+  for i in 0..high(src.data): dest.data[i] = src.data[i]
 
 proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) =
   dest.counter = src.counter
-  setLen(dest.data, len(src.data))
-  for i in 0 .. high(src.data): dest.data[i] = src.data[i]
+  setLen(dest.data, src.data.len)
+  for i in 0..high(src.data): dest.data[i] = src.data[i]
 
 proc discardSons*(father: PNode) =
   when defined(nimNoNilSeqs):
@@ -1286,12 +1286,6 @@ proc newStrNode*(strVal: string; info: TLineInfo): PNode =
   result = newNodeI(nkStrLit, info)
   result.strVal = strVal
 
-proc addSon*(father, son: PNode) =
-  assert son != nil
-  when not defined(nimNoNilSeqs):
-    if isNil(father.sons): father.sons = @[]
-  add(father.sons, son)
-
 proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
                  params,
                  name, pattern, genericParams,
@@ -1366,8 +1360,8 @@ proc assignType*(dest, src: PType) =
       mergeLoc(dest.sym.loc, src.sym.loc)
     else:
       dest.sym = src.sym
-  newSons(dest, len(src))
-  for i in 0 ..< len(src): dest.sons[i] = src.sons[i]
+  newSons(dest, src.len)
+  for i in 0..<src.len: dest[i] = src[i]
 
 proc copyType*(t: PType, owner: PSym, keepId: bool): PType =
   result = newType(t.kind, owner)
@@ -1503,27 +1497,26 @@ proc propagateToOwner*(owner, elem: PType) =
 proc rawAddSon*(father, son: PType) =
   when not defined(nimNoNilSeqs):
     if isNil(father.sons): father.sons = @[]
-  add(father.sons, son)
+  father.sons.add(son)
   if not son.isNil: propagateToOwner(father, son)
 
 proc rawAddSonNoPropagationOfTypeFlags*(father, son: PType) =
   when not defined(nimNoNilSeqs):
     if isNil(father.sons): father.sons = @[]
-  add(father.sons, son)
+  father.sons.add(son)
 
 proc addSonNilAllowed*(father, son: PNode) =
   when not defined(nimNoNilSeqs):
     if isNil(father.sons): father.sons = @[]
-  add(father.sons, son)
+  father.sons.add(son)
 
 proc delSon*(father: PNode, idx: int) =
   when defined(nimNoNilSeqs):
     if father.len == 0: return
   else:
     if isNil(father.sons): return
-  var length = len(father)
-  for i in idx .. length - 2: father.sons[i] = father.sons[i + 1]
-  setLen(father.sons, length - 1)
+  for i in idx..<father.len - 1: father[i] = father[i + 1]
+  father.sons.setLen(father.len - 1)
 
 proc copyNode*(src: PNode): PNode =
   # does not copy its sons!
@@ -1562,7 +1555,7 @@ proc shallowCopy*(src: PNode): PNode =
   of nkSym: result.sym = src.sym
   of nkIdent: result.ident = src.ident
   of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
-  else: newSeq(result.sons, len(src))
+  else: newSeq(result.sons, src.len)
 
 proc copyTree*(src: PNode): PNode =
   # copy a whole syntax tree; performs deep copying
@@ -1583,21 +1576,21 @@ proc copyTree*(src: PNode): PNode =
   of nkIdent: result.ident = src.ident
   of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
   else:
-    newSeq(result.sons, len(src))
-    for i in 0 ..< len(src):
-      result.sons[i] = copyTree(src.sons[i])
+    newSeq(result.sons, src.len)
+    for i in 0..<src.len:
+      result[i] = copyTree(src[i])
 
 proc hasSonWith*(n: PNode, kind: TNodeKind): bool =
-  for i in 0 ..< len(n):
-    if n.sons[i].kind == kind:
+  for i in 0..<n.len:
+    if n[i].kind == kind:
       return true
   result = false
 
 proc hasNilSon*(n: PNode): bool =
-  for i in 0 ..< safeLen(n):
-    if n.sons[i] == nil:
+  for i in 0..<n.safeLen:
+    if n[i] == nil:
       return true
-    elif hasNilSon(n.sons[i]):
+    elif hasNilSon(n[i]):
       return true
   result = false
 
@@ -1606,15 +1599,15 @@ proc containsNode*(n: PNode, kinds: TNodeKinds): bool =
   case n.kind
   of nkEmpty..nkNilLit: result = n.kind in kinds
   else:
-    for i in 0 ..< len(n):
-      if n.kind in kinds or containsNode(n.sons[i], kinds): return true
+    for i in 0..<n.len:
+      if n.kind in kinds or containsNode(n[i], kinds): return true
 
 proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool =
   case n.kind
   of nkEmpty..nkNilLit: result = n.kind == kind
   else:
-    for i in 0 ..< len(n):
-      if (n.sons[i].kind == kind) or hasSubnodeWith(n.sons[i], kind):
+    for i in 0..<n.len:
+      if (n[i].kind == kind) or hasSubnodeWith(n[i], kind):
         return true
     result = false
 
@@ -1710,19 +1703,19 @@ proc requiredParams*(s: PSym): int =
   # Returns the number of required params (without default values)
   # XXX: Perhaps we can store this in the `offset` field of the
   # symbol instead?
-  for i in 1 ..< s.typ.len:
+  for i in 1..<s.typ.len:
     if s.typ.n[i].sym.ast != nil:
       return i - 1
   return s.typ.len - 1
 
 proc hasPattern*(s: PSym): bool {.inline.} =
-  result = isRoutine(s) and s.ast.sons[patternPos].kind != nkEmpty
+  result = isRoutine(s) and s.ast[patternPos].kind != nkEmpty
 
 iterator items*(n: PNode): PNode =
-  for i in 0..<n.safeLen: yield n.sons[i]
+  for i in 0..<n.safeLen: yield n[i]
 
 iterator pairs*(n: PNode): tuple[i: int, n: PNode] =
-  for i in 0..<n.safeLen: yield (i, n.sons[i])
+  for i in 0..<n.safeLen: yield (i, n[i])
 
 proc isAtom*(n: PNode): bool {.inline.} =
   result = n.kind >= nkNone and n.kind <= nkNilLit
@@ -1740,7 +1733,7 @@ proc makeStmtList*(n: PNode): PNode =
 
 proc skipStmtList*(n: PNode): PNode =
   if n.kind in {nkStmtList, nkStmtListExpr}:
-    for i in 0 .. n.len-2:
+    for i in 0..<n.len-1:
       if n[i].kind notin {nkEmpty, nkCommentStmt}: return n
     result = n.lastSon
   else:
@@ -1797,7 +1790,7 @@ when false:
   proc containsNil*(n: PNode): bool =
     # only for debugging
     if n.isNil: return true
-    for i in 0 ..< n.safeLen:
+    for i in 0..<n.safeLen:
       if n[i].containsNil: return true
 
 template hasDestructor*(t: PType): bool = {tfHasAsgn, tfHasOwned} * t.flags != {}
@@ -1831,11 +1824,11 @@ proc newProcType*(info: TLineInfo; owner: PSym): PType =
   # result.n[0] used to be `nkType`, but now it's `nkEffectList` because
   # the effects are now stored in there too ... this is a bit hacky, but as
   # usual we desperately try to save memory:
-  addSon(result.n, newNodeI(nkEffectList, info))
+  result.n.add newNodeI(nkEffectList, info)
 
 proc addParam*(procType: PType; param: PSym) =
   param.position = procType.len-1
-  addSon(procType.n, newSymNode(param))
+  procType.n.add newSymNode(param)
   rawAddSon(procType, param.typ)
 
 template destructor*(t: PType): PSym = t.attachedOps[attachedDestructor]
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index e39608999..f228de1ca 100644
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -116,9 +116,9 @@ proc skipConvAndClosure*(n: PNode): PNode =
     case result.kind
     of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64,
        nkClosure:
-      result = result.sons[0]
+      result = result[0]
     of nkHiddenStdConv, nkHiddenSubConv, nkConv:
-      result = result.sons[1]
+      result = result[1]
     else: break
 
 proc sameValue*(a, b: PNode): bool =
@@ -160,17 +160,17 @@ proc lookupInRecord(n: PNode, field: PIdent): PSym =
   result = nil
   case n.kind
   of nkRecList:
-    for i in 0 ..< len(n):
-      result = lookupInRecord(n.sons[i], field)
+    for i in 0..<n.len:
+      result = lookupInRecord(n[i], field)
       if result != nil: return
   of nkRecCase:
-    if (n.sons[0].kind != nkSym): return nil
-    result = lookupInRecord(n.sons[0], field)
+    if (n[0].kind != nkSym): return nil
+    result = lookupInRecord(n[0], field)
     if result != nil: return
-    for i in 1 ..< len(n):
-      case n.sons[i].kind
+    for i in 1..<n.len:
+      case n[i].kind
       of nkOfBranch, nkElse:
-        result = lookupInRecord(lastSon(n.sons[i]), field)
+        result = lookupInRecord(lastSon(n[i]), field)
         if result != nil: return
       else: return nil
   of nkSym:
@@ -183,9 +183,9 @@ proc getModule*(s: PSym): PSym =
   while result != nil and result.kind != skModule: result = result.owner
 
 proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym =
-  for i in start ..< len(list):
-    if list.sons[i].kind == nkSym:
-      result = list.sons[i].sym
+  for i in start..<list.len:
+    if list[i].kind == nkSym:
+      result = list[i].sym
       if result.name.id == ident.id: return
     else: return nil
   result = nil
@@ -221,11 +221,11 @@ proc getNamedParamFromList*(list: PNode, ident: PIdent): PSym =
   ## gensym'ed and then they have '`<number>' suffix that we need to
   ## ignore, see compiler / evaltempl.nim, snippet:
   ##
-  ## .. code-block:: nim
+  ##..code-block:: nim
   ##
   ##    result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $x.id),
   ##            if c.instLines: actual.info else: templ.info)
-  for i in 1 ..< len(list):
+  for i in 1..<list.len:
     let it = list[i].sym
     if it.name.id == ident.id or
         sameIgnoreBacktickGensymInfo(it.name.s, ident.s): return it
@@ -254,15 +254,15 @@ proc makeYamlString*(s: string): Rope =
   const MaxLineLength = 64
   result = nil
   var res = "\""
-  for i in 0 ..< s.len:
+  for i in 0..<s.len:
     if (i + 1) mod MaxLineLength == 0:
-      add(res, '\"')
-      add(res, "\n")
-      add(result, rope(res))
+      res.add('\"')
+      res.add("\n")
+      result.add(rope(res))
       res = "\""              # reset
-    add(res, toYamlChar(s[i]))
-  add(res, '\"')
-  add(result, rope(res))
+    res.add(toYamlChar(s[i]))
+  res.add('\"')
+  result.add(rope(res))
 
 proc flagsToStr[T](flags: set[T]): Rope =
   if flags == {}:
@@ -270,8 +270,8 @@ proc flagsToStr[T](flags: set[T]): Rope =
   else:
     result = nil
     for x in items(flags):
-      if result != nil: add(result, ", ")
-      add(result, makeYamlString($x))
+      if result != nil: result.add(", ")
+      result.add(makeYamlString($x))
     result = "[" & result & "]"
 
 proc lineInfoToStr(conf: ConfigRef; info: TLineInfo): Rope =
@@ -298,25 +298,25 @@ proc symToYamlAux(conf: ConfigRef; n: PSym, marker: var IntSet, indent: int,
                                  #  indent + 2, maxRecDepth - 1),
     let istr = rspaces(indent + 2)
     result = rope("{")
-    addf(result, "$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
-    addf(result, "$N$1\"name\": $2", [istr, makeYamlString(n.name.s)])
-    addf(result, "$N$1\"typ\": $2", [istr, typeToYamlAux(conf, n.typ, marker, indent + 2, maxRecDepth - 1)])
+    result.addf("$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
+    result.addf("$N$1\"name\": $2", [istr, makeYamlString(n.name.s)])
+    result.addf("$N$1\"typ\": $2", [istr, typeToYamlAux(conf, n.typ, marker, indent + 2, maxRecDepth - 1)])
     if conf != nil:
       # if we don't pass the config, we probably don't care about the line info
-      addf(result, "$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)])
+      result.addf("$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)])
     if card(n.flags) > 0:
-      addf(result, "$N$1\"flags\": $2", [istr, flagsToStr(n.flags)])
-    addf(result, "$N$1\"magic\": $2", [istr, makeYamlString($n.magic)])
-    addf(result, "$N$1\"ast\": $2", [istr, ast])
-    addf(result, "$N$1\"options\": $2", [istr, flagsToStr(n.options)])
-    addf(result, "$N$1\"position\": $2", [istr, rope(n.position)])
-    addf(result, "$N$1\"k\": $2", [istr, makeYamlString($n.loc.k)])
-    addf(result, "$N$1\"storage\": $2", [istr, makeYamlString($n.loc.storage)])
+      result.addf("$N$1\"flags\": $2", [istr, flagsToStr(n.flags)])
+    result.addf("$N$1\"magic\": $2", [istr, makeYamlString($n.magic)])
+    result.addf("$N$1\"ast\": $2", [istr, ast])
+    result.addf("$N$1\"options\": $2", [istr, flagsToStr(n.options)])
+    result.addf("$N$1\"position\": $2", [istr, rope(n.position)])
+    result.addf("$N$1\"k\": $2", [istr, makeYamlString($n.loc.k)])
+    result.addf("$N$1\"storage\": $2", [istr, makeYamlString($n.loc.storage)])
     if card(n.loc.flags) > 0:
-      addf(result, "$N$1\"flags\": $2", [istr, makeYamlString($n.loc.flags)])
-    addf(result, "$N$1\"r\": $2", [istr, n.loc.r])
-    addf(result, "$N$1\"lode\": $2", [istr, treeToYamlAux(conf, n.loc.lode, marker, indent + 2, maxRecDepth - 1)])
-    addf(result, "$N$1}", [rspaces(indent)])
+      result.addf("$N$1\"flags\": $2", [istr, makeYamlString($n.loc.flags)])
+    result.addf("$N$1\"r\": $2", [istr, n.loc.r])
+    result.addf("$N$1\"lode\": $2", [istr, treeToYamlAux(conf, n.loc.lode, marker, indent + 2, maxRecDepth - 1)])
+    result.addf("$N$1}", [rspaces(indent)])
 
 proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int,
                    maxRecDepth: int): Rope =
@@ -327,27 +327,27 @@ proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int,
     sonsRope = "\"$1 @$2\"" % [rope($n.kind), rope(
         strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
   else:
-    if len(n) > 0:
+    if n.len > 0:
       sonsRope = rope("[")
-      for i in 0 ..< len(n):
-        if i > 0: add(sonsRope, ",")
-        addf(sonsRope, "$N$1$2", [rspaces(indent + 4), typeToYamlAux(conf, n.sons[i],
+      for i in 0..<n.len:
+        if i > 0: sonsRope.add(",")
+        sonsRope.addf("$N$1$2", [rspaces(indent + 4), typeToYamlAux(conf, n[i],
             marker, indent + 4, maxRecDepth - 1)])
-      addf(sonsRope, "$N$1]", [rspaces(indent + 2)])
+      sonsRope.addf("$N$1]", [rspaces(indent + 2)])
     else:
       sonsRope = rope("null")
 
     let istr = rspaces(indent + 2)
     result = rope("{")
-    addf(result, "$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
-    addf(result, "$N$1\"sym\": $2",  [istr, symToYamlAux(conf, n.sym, marker, indent + 2, maxRecDepth - 1)])
-    addf(result, "$N$1\"n\": $2",     [istr, treeToYamlAux(conf, n.n, marker, indent + 2, maxRecDepth - 1)])
+    result.addf("$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
+    result.addf("$N$1\"sym\": $2",  [istr, symToYamlAux(conf, n.sym, marker, indent + 2, maxRecDepth - 1)])
+    result.addf("$N$1\"n\": $2",     [istr, treeToYamlAux(conf, n.n, marker, indent + 2, maxRecDepth - 1)])
     if card(n.flags) > 0:
-      addf(result, "$N$1\"flags\": $2", [istr, flagsToStr(n.flags)])
-    addf(result, "$N$1\"callconv\": $2", [istr, makeYamlString(CallingConvToStr[n.callConv])])
-    addf(result, "$N$1\"size\": $2", [istr, rope(n.size)])
-    addf(result, "$N$1\"align\": $2", [istr, rope(n.align)])
-    addf(result, "$N$1\"sons\": $2", [istr, sonsRope])
+      result.addf("$N$1\"flags\": $2", [istr, flagsToStr(n.flags)])
+    result.addf("$N$1\"callconv\": $2", [istr, makeYamlString(CallingConvToStr[n.callConv])])
+    result.addf("$N$1\"size\": $2", [istr, rope(n.size)])
+    result.addf("$N$1\"align\": $2", [istr, rope(n.align)])
+    result.addf("$N$1\"sons\": $2", [istr, sonsRope])
 
 proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet, indent: int,
                    maxRecDepth: int): Rope =
@@ -358,34 +358,34 @@ proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet, indent: int,
     result = "{$N$1\"kind\": $2" % [istr, makeYamlString($n.kind)]
     if maxRecDepth != 0:
       if conf != nil:
-        addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)])
+        result.addf(",$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)])
       case n.kind
       of nkCharLit..nkInt64Lit:
-        addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
+        result.addf(",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
       of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
-        addf(result, ",$N$1\"floatVal\": $2",
+        result.addf(",$N$1\"floatVal\": $2",
             [istr, rope(n.floatVal.toStrMaxPrecision)])
       of nkStrLit..nkTripleStrLit:
-        addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
+        result.addf(",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
       of nkSym:
-        addf(result, ",$N$1\"sym\": $2",
+        result.addf(",$N$1\"sym\": $2",
              [istr, symToYamlAux(conf, n.sym, marker, indent + 2, maxRecDepth)])
       of nkIdent:
         if n.ident != nil:
-          addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
+          result.addf(",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
         else:
-          addf(result, ",$N$1\"ident\": null", [istr])
+          result.addf(",$N$1\"ident\": null", [istr])
       else:
-        if len(n) > 0:
-          addf(result, ",$N$1\"sons\": [", [istr])
-          for i in 0 ..< len(n):
-            if i > 0: add(result, ",")
-            addf(result, "$N$1$2", [rspaces(indent + 4), treeToYamlAux(conf, n.sons[i],
+        if n.len > 0:
+          result.addf(",$N$1\"sons\": [", [istr])
+          for i in 0..<n.len:
+            if i > 0: result.add(",")
+            result.addf("$N$1$2", [rspaces(indent + 4), treeToYamlAux(conf, n[i],
                 marker, indent + 4, maxRecDepth - 1)])
-          addf(result, "$N$1]", [istr])
-      addf(result, ",$N$1\"typ\": $2",
+          result.addf("$N$1]", [istr])
+      result.addf(",$N$1\"typ\": $2",
            [istr, typeToYamlAux(conf, n.typ, marker, indent + 2, maxRecDepth)])
-    addf(result, "$N$1}", [rspaces(indent)])
+    result.addf("$N$1}", [rspaces(indent)])
 
 proc treeToYaml(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope =
   var marker = initIntSet()
@@ -427,7 +427,7 @@ proc indentLess(this: var DebugPrinter) =
 proc newlineAndIndent(this: var DebugPrinter) =
   this.res.add "\n"
   this.currentLine += 1
-  for i in 0 ..< this.indent:
+  for i in 0..<this.indent:
     this.res.add ' '
 
 proc openCurly(this: var DebugPrinter) =
@@ -563,12 +563,12 @@ proc value(this: var DebugPrinter; value: PType) =
     this.key "n"
     this.value value.n
 
-  if len(value) > 0:
+  if value.len > 0:
     this.key "sons"
     this.openBracket
-    for i in 0 ..< len(value):
-      this.value value.sons[i]
-      if i != len(value) - 1:
+    for i in 0..<value.len:
+      this.value value[i]
+      if i != value.len - 1:
         this.comma
     this.closeBracket
 
@@ -616,12 +616,12 @@ proc value(this: var DebugPrinter; value: PNode) =
     if this.renderSymType and value.typ != nil:
       this.key "typ"
       this.value value.typ
-    if len(value) > 0:
+    if value.len > 0:
       this.key "sons"
       this.openBracket
-      for i in 0 ..< len(value):
-        this.value value.sons[i]
-        if i != len(value) - 1:
+      for i in 0..<value.len:
+        this.value value[i]
+        if i != value.len - 1:
           this.comma
       this.closeBracket
 
@@ -677,13 +677,13 @@ proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) =
 
 proc objectSetEnlarge(t: var TObjectSet) =
   var n: TObjectSeq
-  newSeq(n, len(t.data) * GrowthFactor)
-  for i in 0 .. high(t.data):
+  newSeq(n, t.data.len * GrowthFactor)
+  for i in 0..high(t.data):
     if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
   swap(t.data, n)
 
 proc objectSetIncl*(t: var TObjectSet, obj: RootRef) =
-  if mustRehash(len(t.data), t.counter): objectSetEnlarge(t)
+  if mustRehash(t.data.len, t.counter): objectSetEnlarge(t)
   objectSetRawInsert(t.data, obj)
   inc(t.counter)
 
@@ -696,7 +696,7 @@ proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool =
     if it == obj:
       return true             # found it
     h = nextTry(h, high(t.data))
-  if mustRehash(len(t.data), t.counter):
+  if mustRehash(t.data.len, t.counter):
     objectSetEnlarge(t)
     objectSetRawInsert(t.data, obj)
   else:
@@ -739,13 +739,13 @@ proc symTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
 
 proc strTableEnlarge(t: var TStrTable) =
   var n: seq[PSym]
-  newSeq(n, len(t.data) * GrowthFactor)
-  for i in 0 .. high(t.data):
+  newSeq(n, t.data.len * GrowthFactor)
+  for i in 0..high(t.data):
     if t.data[i] != nil: strTableRawInsert(n, t.data[i])
   swap(t.data, n)
 
 proc strTableAdd*(t: var TStrTable, n: PSym) =
-  if mustRehash(len(t.data), t.counter): strTableEnlarge(t)
+  if mustRehash(t.data.len, t.counter): strTableEnlarge(t)
   strTableRawInsert(t.data, n)
   inc(t.counter)
 
@@ -772,7 +772,7 @@ proc strTableInclReportConflict*(t: var TStrTable, n: PSym;
     if not onConflictKeepOld:
       t.data[replaceSlot] = n # overwrite it with newer definition!
     return t.data[replaceSlot] # found it
-  elif mustRehash(len(t.data), t.counter):
+  elif mustRehash(t.data.len, t.counter):
     strTableEnlarge(t)
     strTableRawInsert(t.data, n)
   else:
@@ -876,7 +876,7 @@ iterator items*(tab: TStrTable): PSym =
     s = nextIter(it, tab)
 
 proc hasEmptySlot(data: TIdPairSeq): bool =
-  for h in 0 .. high(data):
+  for h in 0..high(data):
     if data[h].key == nil:
       return true
   result = false
@@ -929,9 +929,9 @@ proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) =
     assert(t.data[index].key != nil)
     t.data[index].val = val
   else:
-    if mustRehash(len(t.data), t.counter):
-      newSeq(n, len(t.data) * GrowthFactor)
-      for i in 0 .. high(t.data):
+    if mustRehash(t.data.len, t.counter):
+      newSeq(n, t.data.len * GrowthFactor)
+      for i in 0..high(t.data):
         if t.data[i].key != nil:
           idTableRawInsert(n, t.data[i].key, t.data[i].val)
       assert(hasEmptySlot(n))
@@ -940,7 +940,7 @@ proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) =
     inc(t.counter)
 
 iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] =
-  for i in 0 .. high(t.data):
+  for i in 0..high(t.data):
     if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
 
 proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
@@ -974,10 +974,10 @@ proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
     assert(t.data[index].key != nil)
     t.data[index].val = val
   else:
-    if mustRehash(len(t.data), t.counter):
+    if mustRehash(t.data.len, t.counter):
       var n: TIdNodePairSeq
-      newSeq(n, len(t.data) * GrowthFactor)
-      for i in 0 .. high(t.data):
+      newSeq(n, t.data.len * GrowthFactor)
+      for i in 0..high(t.data):
         if t.data[i].key != nil:
           idNodeTableRawInsert(n, t.data[i].key, t.data[i].val)
       swap(t.data, n)
@@ -985,13 +985,13 @@ proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
     inc(t.counter)
 
 iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] =
-  for i in 0 .. high(t.data):
+  for i in 0..high(t.data):
     if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
 
 proc initIITable(x: var TIITable) =
   x.counter = 0
   newSeq(x.data, StartSize)
-  for i in 0 ..< StartSize: x.data[i].key = InvalidKey
+  for i in 0..<StartSize: x.data[i].key = InvalidKey
 
 proc iiTableRawGet(t: TIITable, key: int): int =
   var h: Hash
@@ -1022,11 +1022,11 @@ proc iiTablePut(t: var TIITable, key, val: int) =
     assert(t.data[index].key != InvalidKey)
     t.data[index].val = val
   else:
-    if mustRehash(len(t.data), t.counter):
+    if mustRehash(t.data.len, t.counter):
       var n: TIIPairSeq
-      newSeq(n, len(t.data) * GrowthFactor)
-      for i in 0 .. high(n): n[i].key = InvalidKey
-      for i in 0 .. high(t.data):
+      newSeq(n, t.data.len * GrowthFactor)
+      for i in 0..high(n): n[i].key = InvalidKey
+      for i in 0..high(t.data):
         if t.data[i].key != InvalidKey:
           iiTableRawInsert(n, t.data[i].key, t.data[i].val)
       swap(t.data, n)
diff --git a/compiler/bitsets.nim b/compiler/bitsets.nim
index 01f8ca95e..2e8aa1db6 100644
--- a/compiler/bitsets.nim
+++ b/compiler/bitsets.nim
@@ -52,25 +52,25 @@ proc bitSetInit(b: var TBitSet, length: int) =
   newSeq(b, length)
 
 proc bitSetUnion(x: var TBitSet, y: TBitSet) =
-  for i in 0 .. high(x): x[i] = x[i] or y[i]
+  for i in 0..high(x): x[i] = x[i] or y[i]
 
 proc bitSetDiff(x: var TBitSet, y: TBitSet) =
-  for i in 0 .. high(x): x[i] = x[i] and not y[i]
+  for i in 0..high(x): x[i] = x[i] and not y[i]
 
 proc bitSetSymDiff(x: var TBitSet, y: TBitSet) =
-  for i in 0 .. high(x): x[i] = x[i] xor y[i]
+  for i in 0..high(x): x[i] = x[i] xor y[i]
 
 proc bitSetIntersect(x: var TBitSet, y: TBitSet) =
-  for i in 0 .. high(x): x[i] = x[i] and y[i]
+  for i in 0..high(x): x[i] = x[i] and y[i]
 
 proc bitSetEquals(x, y: TBitSet): bool =
-  for i in 0 .. high(x):
+  for i in 0..high(x):
     if x[i] != y[i]:
       return false
   result = true
 
 proc bitSetContains(x, y: TBitSet): bool =
-  for i in 0 .. high(x):
+  for i in 0..high(x):
     if (x[i] and not y[i]) != Zero:
       return false
   result = true
diff --git a/compiler/btrees.nim b/compiler/btrees.nim
index 6cd6e51f4..4f9031a6b 100644
--- a/compiler/btrees.nim
+++ b/compiler/btrees.nim
@@ -37,34 +37,34 @@ template eq(a, b): bool = cmp(a, b) == 0
 proc getOrDefault*[Key, Val](b: BTree[Key, Val], key: Key): Val =
   var x = b.root
   while x.isInternal:
-    for j in 0 ..< x.entries:
+    for j in 0..<x.entries:
       if j+1 == x.entries or less(key, x.keys[j+1]):
         x = x.links[j]
         break
   assert(not x.isInternal)
-  for j in 0 ..< x.entries:
+  for j in 0..<x.entries:
     if eq(key, x.keys[j]): return x.vals[j]
 
 proc contains*[Key, Val](b: BTree[Key, Val], key: Key): bool =
   var x = b.root
   while x.isInternal:
-    for j in 0 ..< x.entries:
+    for j in 0..<x.entries:
       if j+1 == x.entries or less(key, x.keys[j+1]):
         x = x.links[j]
         break
   assert(not x.isInternal)
-  for j in 0 ..< x.entries:
+  for j in 0..<x.entries:
     if eq(key, x.keys[j]): return true
   return false
 
 proc copyHalf[Key, Val](h, result: Node[Key, Val]) =
-  for j in 0 ..< Mhalf:
+  for j in 0..<Mhalf:
     result.keys[j] = h.keys[Mhalf + j]
   if h.isInternal:
-    for j in 0 ..< Mhalf:
+    for j in 0..<Mhalf:
       result.links[j] = h.links[Mhalf + j]
   else:
-    for j in 0 ..< Mhalf:
+    for j in 0..<Mhalf:
       shallowCopy(result.vals[j], h.vals[Mhalf + j])
 
 proc split[Key, Val](h: Node[Key, Val]): Node[Key, Val] =
diff --git a/compiler/canonicalizer.nim b/compiler/canonicalizer.nim
index 1cf6171c1..76c2872f7 100644
--- a/compiler/canonicalizer.nim
+++ b/compiler/canonicalizer.nim
@@ -102,7 +102,7 @@ proc hashTree(c: var MD5Context, n: PNode) =
   of nkStrLit..nkTripleStrLit:
     c &= n.strVal
   else:
-    for i in 0..<n.len: hashTree(c, n.sons[i])
+    for i in 0..<n.len: hashTree(c, n[i])
 
 proc hashType(c: var MD5Context, t: PType) =
   # modelled after 'typeToString'
@@ -120,44 +120,44 @@ proc hashType(c: var MD5Context, t: PType) =
 
   case t.kind
   of tyGenericBody, tyGenericInst, tyGenericInvocation:
-    for i in 0 ..< len(t)-ord(t.kind != tyGenericInvocation):
-      c.hashType t.sons[i]
+    for i in 0..<t.len-ord(t.kind != tyGenericInvocation):
+      c.hashType t[i]
   of tyUserTypeClass:
     internalAssert t.sym != nil and t.sym.owner != nil
     c &= t.sym.owner.name.s
   of tyUserTypeClassInst:
     let body = t.base
     c.hashSym body.sym
-    for i in 1 .. len(t) - 2:
-      c.hashType t.sons[i]
+    for i in 1..<t.len-1:
+      c.hashType t[i]
   of tyFromExpr:
     c.hashTree(t.n)
   of tyArray:
-    c.hashTree(t.sons[0].n)
-    c.hashType(t.sons[1])
+    c.hashTree(t[0].n)
+    c.hashType(t[1])
   of tyTuple:
     if t.n != nil:
-      assert(len(t.n) == len(t))
-      for i in 0 ..< len(t.n):
-        assert(t.n.sons[i].kind == nkSym)
-        c &= t.n.sons[i].sym.name.s
+      assert(t.n.len == t.len)
+      for i in 0..<t.n.len:
+        assert(t.n[i].kind == nkSym)
+        c &= t.n[i].sym.name.s
         c &= ":"
-        c.hashType(t.sons[i])
+        c.hashType(t[i])
         c &= ","
     else:
-      for i in 0 ..< len(t): c.hashType t.sons[i]
+      for i in 0..<t.len: c.hashType t[i]
   of tyRange:
     c.hashTree(t.n)
-    c.hashType(t.sons[0])
+    c.hashType(t[0])
   of tyProc:
     c &= (if tfIterator in t.flags: "iterator " else: "proc ")
-    for i in 0..<t.len: c.hashType(t.sons[i])
+    for i in 0..<t.len: c.hashType(t[i])
     md5Update(c, cast[cstring](addr(t.callConv)), 1)
 
     if tfNoSideEffect in t.flags: c &= ".noSideEffect"
     if tfThread in t.flags: c &= ".thread"
   else:
-    for i in 0..<t.len: c.hashType(t.sons[i])
+    for i in 0..<t.len: c.hashType(t[i])
   if tfNotNil in t.flags: c &= "not nil"
 
 proc canonConst(n: PNode): TUid =
@@ -238,35 +238,35 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
     encodeVInt(n.sym.id, result)
     pushSym(w, n.sym)
   else:
-    for i in 0 ..< len(n):
-      encodeNode(w, n.info, n.sons[i], result)
-  add(result, ')')
+    for i in 0..<n.len:
+      encodeNode(w, n.info, n[i], result)
+  result.add(')')
 
 proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
   var oldLen = result.len
   result.add('<')
   if loc.k != low(loc.k): encodeVInt(ord(loc.k), result)
   if loc.s != low(loc.s):
-    add(result, '*')
+    result.add('*')
     encodeVInt(ord(loc.s), result)
   if loc.flags != {}:
-    add(result, '$')
+    result.add('$')
     encodeVInt(cast[int32](loc.flags), result)
   if loc.t != nil:
-    add(result, '^')
+    result.add('^')
     encodeVInt(cast[int32](loc.t.id), result)
     pushType(w, loc.t)
   if loc.r != nil:
-    add(result, '!')
+    result.add('!')
     encodeStr($loc.r, result)
   if loc.a != 0:
-    add(result, '?')
+    result.add('?')
     encodeVInt(loc.a, result)
   if oldLen + 1 == result.len:
     # no data was necessary, so remove the '<' again:
     setLen(result, oldLen)
   else:
-    add(result, '>')
+    result.add('>')
 
 proc encodeType(w: PRodWriter, t: PType, result: var string) =
   if t == nil:
@@ -277,47 +277,47 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
   if t.kind == tyForward: internalError("encodeType: tyForward")
   # for the new rodfile viewer we use a preceding [ so that the data section
   # can easily be disambiguated:
-  add(result, '[')
+  result.add('[')
   encodeVInt(ord(t.kind), result)
-  add(result, '+')
+  result.add('+')
   encodeVInt(t.id, result)
   if t.n != nil:
     encodeNode(w, unknownLineInfo(), t.n, result)
   if t.flags != {}:
-    add(result, '$')
+    result.add('$')
     encodeVInt(cast[int32](t.flags), result)
   if t.callConv != low(t.callConv):
-    add(result, '?')
+    result.add('?')
     encodeVInt(ord(t.callConv), result)
   if t.owner != nil:
-    add(result, '*')
+    result.add('*')
     encodeVInt(t.owner.id, result)
     pushSym(w, t.owner)
   if t.sym != nil:
-    add(result, '&')
+    result.add('&')
     encodeVInt(t.sym.id, result)
     pushSym(w, t.sym)
   if t.size != - 1:
-    add(result, '/')
+    result.add('/')
     encodeVBiggestInt(t.size, result)
   if t.align != - 1:
-    add(result, '=')
+    result.add('=')
     encodeVInt(t.align, result)
   encodeLoc(w, t.loc, result)
-  for i in 0 ..< len(t):
-    if t.sons[i] == nil:
-      add(result, "^()")
+  for i in 0..<t.len:
+    if t[i] == nil:
+      result.add("^()")
     else:
-      add(result, '^')
-      encodeVInt(t.sons[i].id, result)
-      pushType(w, t.sons[i])
+      result.add('^')
+      encodeVInt(t[i].id, result)
+      pushType(w, t[i])
 
 proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
-  add(result, '|')
+  result.add('|')
   encodeVInt(ord(lib.kind), result)
-  add(result, '|')
+  result.add('|')
   encodeStr($lib.name, result)
-  add(result, '|')
+  result.add('|')
   encodeNode(w, info, lib.path, result)
 
 proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
@@ -363,7 +363,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
   encodeLoc(w, s.loc, result)
   if s.annex != nil: encodeLib(w, s.annex, s.info, result)
   if s.constraint != nil:
-    add(result, '#')
+    result.add('#')
     encodeNode(w, unknownLineInfo(), s.constraint, result)
   # lazy loading will soon reload the ast lazily, so the ast needs to be
   # the last entry of a symbol:
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 686eb8fde..b5fffaddb 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -11,41 +11,41 @@
 
 proc leftAppearsOnRightSide(le, ri: PNode): bool =
   if le != nil:
-    for i in 1 ..< ri.len:
+    for i in 1..<ri.len:
       let r = ri[i]
       if isPartOf(le, r) != arNo: return true
 
 proc hasNoInit(call: PNode): bool {.inline.} =
-  result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags
+  result = call[0].kind == nkSym and sfNoInit in call[0].sym.flags
 
 proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
                callee, params: Rope) =
   genLineDir(p, ri)
   var pl = callee & ~"(" & params
   # getUniqueType() is too expensive here:
-  var typ = skipTypes(ri.sons[0].typ, abstractInst)
-  if typ.sons[0] != nil:
-    if isInvalidReturnType(p.config, typ.sons[0]):
+  var typ = skipTypes(ri[0].typ, abstractInst)
+  if typ[0] != nil:
+    if isInvalidReturnType(p.config, typ[0]):
       if params != nil: pl.add(~", ")
       # beware of 'result = p(result)'. We may need to allocate a temporary:
       if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
         # Great, we can use 'd':
-        if d.k == locNone: getTemp(p, typ.sons[0], d, needsInit=true)
+        if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
         elif d.k notin {locTemp} and not hasNoInit(ri):
           # reset before pass as 'result' var:
           discard "resetLoc(p, d)"
-        add(pl, addrLoc(p.config, d))
-        add(pl, ~");$n")
+        pl.add(addrLoc(p.config, d))
+        pl.add(~");$n")
         line(p, cpsStmts, pl)
       else:
         var tmp: TLoc
-        getTemp(p, typ.sons[0], tmp, needsInit=true)
-        add(pl, addrLoc(p.config, tmp))
-        add(pl, ~");$n")
+        getTemp(p, typ[0], tmp, needsInit=true)
+        pl.add(addrLoc(p.config, tmp))
+        pl.add(~");$n")
         line(p, cpsStmts, pl)
         genAssignment(p, d, tmp, {}) # no need for deep copying
     else:
-      add(pl, ~")")
+      pl.add(~")")
       if p.module.compileToCpp:
         if lfSingleUse in d.flags:
           # do not generate spurious temporaries for C++! For C we're better off
@@ -56,22 +56,22 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
           excl d.flags, lfSingleUse
         else:
           if d.k == locNone and p.splitDecls == 0:
-            getTempCpp(p, typ.sons[0], d, pl)
+            getTempCpp(p, typ[0], d, pl)
           else:
-            if d.k == locNone: getTemp(p, typ.sons[0], d)
+            if d.k == locNone: getTemp(p, typ[0], d)
             var list: TLoc
             initLoc(list, locCall, d.lode, OnUnknown)
             list.r = pl
             genAssignment(p, d, list, {}) # no need for deep copying
       else:
-        if d.k == locNone: getTemp(p, typ.sons[0], d)
+        if d.k == locNone: getTemp(p, typ[0], d)
         assert(d.t != nil)        # generate an assignment to d:
         var list: TLoc
         initLoc(list, locCall, d.lode, OnUnknown)
         list.r = pl
         genAssignment(p, d, list, {}) # no need for deep copying
   else:
-    add(pl, ~");$n")
+    pl.add(~");$n")
     line(p, cpsStmts, pl)
 
 proc genBoundsCheck(p: BProc; arr, a, b: TLoc)
@@ -89,7 +89,7 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
     if skipped:
       q = skipConv(n)
       while q.kind == nkStmtListExpr and q.len > 0:
-        for i in 0..q.len-2:
+        for i in 0..<q.len-1:
           genStmts(p, q[i])
         q = q.lastSon
     var b, c: TLoc
@@ -100,7 +100,7 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
     if optBoundsCheck in p.options:
       genBoundsCheck(p, a, b, c)
     let ty = skipTypes(a.t, abstractVar+{tyPtr})
-    let dest = getTypeDesc(p.module, n.typ.sons[0])
+    let dest = getTypeDesc(p.module, n.typ[0])
     case ty.kind
     of tyArray:
       let first = toInt64(firstOrd(p.config, ty))
@@ -148,7 +148,7 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
 
 proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} =
   var a: TLoc
-  initLocExpr(p, n.sons[0], a)
+  initLocExpr(p, n[0], a)
   result = ropecg(p.module, "#nimToCStringConv($1)", [a.rdLoc])
 
 proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope =
@@ -156,17 +156,17 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope =
   if n.kind == nkStringToCString:
     result = genArgStringToCString(p, n)
   elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
-    var n = if n.kind != nkHiddenAddr: n else: n.sons[0]
+    var n = if n.kind != nkHiddenAddr: n else: n[0]
     result = openArrayLoc(p, n)
   elif ccgIntroducedPtr(p.config, param, call[0].typ[0]):
     initLocExpr(p, n, a)
     result = addrLoc(p.config, a)
   elif p.module.compileToCpp and param.typ.kind == tyVar and
       n.kind == nkHiddenAddr:
-    initLocExprSingleUse(p, n.sons[0], a)
+    initLocExprSingleUse(p, n[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]
+    let callee = call[0]
     if callee.kind == nkSym and
         {sfImportc, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportc} and
         {lfHeader, lfNoDecl} * callee.sym.loc.flags != {}:
@@ -186,15 +186,15 @@ proc genArgNoParam(p: BProc, n: PNode): Rope =
     result = rdLoc(a)
 
 template genParamLoop(params) {.dirty.} =
-  if i < len(typ):
-    assert(typ.n.sons[i].kind == nkSym)
-    let paramType = typ.n.sons[i]
+  if i < typ.len:
+    assert(typ.n[i].kind == nkSym)
+    let paramType = typ.n[i]
     if not paramType.typ.isCompileTimeOnly:
-      if params != nil: add(params, ~", ")
-      add(params, genArg(p, ri.sons[i], paramType.sym, ri))
+      if params != nil: params.add(~", ")
+      params.add(genArg(p, ri[i], paramType.sym, ri))
   else:
-    if params != nil: add(params, ~", ")
-    add(params, genArgNoParam(p, ri.sons[i]))
+    if params != nil: params.add(~", ")
+    params.add(genArgNoParam(p, ri[i]))
 
 proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) =
   if sym.flags * {sfImportc, sfNonReloadable} == {} and sym.loc.k == locProc and
@@ -204,18 +204,17 @@ proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) =
 proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
   var op: TLoc
   # this is a hotspot in the compiler
-  initLocExpr(p, ri.sons[0], op)
+  initLocExpr(p, ri[0], op)
   var params: Rope
   # getUniqueType() is too expensive here:
-  var typ = skipTypes(ri.sons[0].typ, abstractInstOwned)
+  var typ = skipTypes(ri[0].typ, abstractInstOwned)
   assert(typ.kind == tyProc)
-  assert(len(typ) == len(typ.n))
-  var length = len(ri)
-  for i in 1 ..< length:
+  assert(typ.len == typ.n.len)
+  for i in 1..<ri.len:
     genParamLoop(params)
   var callee = rdLoc(op)
-  if p.hcrOn and ri.sons[0].kind == nkSym:
-    callee.addActualSuffixForHCR(p.module.module, ri.sons[0].sym)
+  if p.hcrOn and ri[0].kind == nkSym:
+    callee.addActualSuffixForHCR(p.module.module, ri[0].sym)
   fixupCall(p, le, ri, d, callee, params)
 
 proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
@@ -229,14 +228,13 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
   const PatProc = "$1.ClE_0? $1.ClP_0($3$1.ClE_0):(($4)($1.ClP_0))($2)"
   const PatIter = "$1.ClP_0($3$1.ClE_0)" # we know the env exists
   var op: TLoc
-  initLocExpr(p, ri.sons[0], op)
+  initLocExpr(p, ri[0], op)
   var pl: Rope
 
-  var typ = skipTypes(ri.sons[0].typ, abstractInst)
+  var typ = skipTypes(ri[0].typ, abstractInst)
   assert(typ.kind == tyProc)
-  var length = len(ri)
-  for i in 1 ..< length:
-    assert(len(typ) == len(typ.n))
+  for i in 1..<ri.len:
+    assert(typ.len == typ.n.len)
     genParamLoop(pl)
 
   template genCallPattern {.dirty.} =
@@ -246,27 +244,27 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
       lineF(p, cpsStmts, PatProc & ";$n", [rdLoc(op), pl, pl.addComma, rawProc])
 
   let rawProc = getRawProcType(p, typ)
-  if typ.sons[0] != nil:
-    if isInvalidReturnType(p.config, typ.sons[0]):
-      if len(ri) > 1: add(pl, ~", ")
+  if typ[0] != nil:
+    if isInvalidReturnType(p.config, typ[0]):
+      if ri.len > 1: pl.add(~", ")
       # beware of 'result = p(result)'. We may need to allocate a temporary:
       if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
         # Great, we can use 'd':
         if d.k == locNone:
-          getTemp(p, typ.sons[0], d, needsInit=true)
+          getTemp(p, typ[0], d, needsInit=true)
         elif d.k notin {locTemp} and not hasNoInit(ri):
           # reset before pass as 'result' var:
           discard "resetLoc(p, d)"
-        add(pl, addrLoc(p.config, d))
+        pl.add(addrLoc(p.config, d))
         genCallPattern()
       else:
         var tmp: TLoc
-        getTemp(p, typ.sons[0], tmp, needsInit=true)
-        add(pl, addrLoc(p.config, tmp))
+        getTemp(p, typ[0], tmp, needsInit=true)
+        pl.add(addrLoc(p.config, tmp))
         genCallPattern()
         genAssignment(p, d, tmp, {}) # no need for deep copying
     else:
-      if d.k == locNone: getTemp(p, typ.sons[0], d)
+      if d.k == locNone: getTemp(p, typ[0], d)
       assert(d.t != nil)        # generate an assignment to d:
       var list: TLoc
       initLoc(list, locCall, d.lode, OnUnknown)
@@ -280,23 +278,23 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
     genCallPattern()
 
 proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
-  if i < len(typ):
+  if i < typ.len:
     # 'var T' is 'T&' in C++. This means we ignore the request of
     # any nkHiddenAddr when it's a 'var T'.
-    let paramType = typ.n.sons[i]
+    let paramType = typ.n[i]
     assert(paramType.kind == nkSym)
     if paramType.typ.isCompileTimeOnly:
       result = nil
-    elif typ.sons[i].kind == tyVar and ri.sons[i].kind == nkHiddenAddr:
-      result = genArgNoParam(p, ri.sons[i][0])
+    elif typ[i].kind == tyVar and ri[i].kind == nkHiddenAddr:
+      result = genArgNoParam(p, ri[i][0])
     else:
-      result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym)
+      result = genArgNoParam(p, ri[i]) #, typ.n[i].sym)
   else:
     if tfVarargs notin typ.flags:
       localError(p.config, ri.info, "wrong argument count")
       result = nil
     else:
-      result = genArgNoParam(p, ri.sons[i])
+      result = genArgNoParam(p, ri[i])
 
 discard """
 Dot call syntax in C++
@@ -340,16 +338,16 @@ proc skipAddrDeref(node: PNode): PNode =
   var isAddr = false
   case n.kind
   of nkAddr, nkHiddenAddr:
-    n = n.sons[0]
+    n = n[0]
     isAddr = true
   of nkDerefExpr, nkHiddenDeref:
-    n = n.sons[0]
+    n = n[0]
   else: return n
-  if n.kind == nkObjDownConv: n = n.sons[0]
+  if n.kind == nkObjDownConv: n = n[0]
   if isAddr and n.kind in {nkDerefExpr, nkHiddenDeref}:
-    result = n.sons[0]
+    result = n[0]
   elif n.kind in {nkAddr, nkHiddenAddr}:
-    result = n.sons[0]
+    result = n[0]
   else:
     result = node
 
@@ -357,13 +355,13 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
   # for better or worse c2nim translates the 'this' argument to a 'var T'.
   # However manual wrappers may also use 'ptr T'. In any case we support both
   # for convenience.
-  internalAssert p.config, i < len(typ)
-  assert(typ.n.sons[i].kind == nkSym)
+  internalAssert p.config, i < typ.len
+  assert(typ.n[i].kind == nkSym)
   # if the parameter is lying (tyVar) and thus we required an additional deref,
   # skip the deref:
   var ri = ri[i]
   while ri.kind == nkObjDownConv: ri = ri[0]
-  let t = typ.sons[i].skipTypes({tyGenericInst, tyAlias, tySink})
+  let t = typ[i].skipTypes({tyGenericInst, tyAlias, tySink})
   if t.kind == tyVar:
     let x = if ri.kind == nkHiddenAddr: ri[0] else: ri
     if x.typ.kind == tyPtr:
@@ -385,7 +383,7 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
   else:
     ri = skipAddrDeref(ri)
     if ri.kind in {nkAddr, nkHiddenAddr}: ri = ri[0]
-    result = genArgNoParam(p, ri) #, typ.n.sons[i].sym)
+    result = genArgNoParam(p, ri) #, typ.n[i].sym)
     result.add(".")
 
 proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope =
@@ -395,7 +393,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope =
     case pat[i]
     of '@':
       var first = true
-      for k in j ..< ri.len:
+      for k in j..<ri.len:
         let arg = genOtherArg(p, ri, k, typ)
         if arg.len > 0:
           if not first:
@@ -407,12 +405,12 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope =
       if i+1 < pat.len and pat[i+1] in {'+', '@'}:
         let ri = ri[j]
         if ri.kind in nkCallKinds:
-          let typ = skipTypes(ri.sons[0].typ, abstractInst)
-          if pat[i+1] == '+': result.add genArgNoParam(p, ri.sons[0])
+          let typ = skipTypes(ri[0].typ, abstractInst)
+          if pat[i+1] == '+': result.add genArgNoParam(p, ri[0])
           result.add(~"(")
           if 1 < ri.len:
             result.add genOtherArg(p, ri, 1, typ)
-          for k in j+1 ..< ri.len:
+          for k in j+1..<ri.len:
             result.add(~", ")
             result.add genOtherArg(p, ri, k, typ)
           result.add(~")")
@@ -423,7 +421,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope =
         result.add genThisArg(p, ri, j, typ)
         inc i
       elif i+1 < pat.len and pat[i+1] == '[':
-        var arg = ri.sons[j].skipAddrDeref
+        var arg = ri[j].skipAddrDeref
         while arg.kind in {nkAddr, nkHiddenAddr, nkObjDownConv}: arg = arg[0]
         result.add genArgNoParam(p, arg)
         #result.add debugTree(arg, 0, 10)
@@ -443,24 +441,23 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope =
         if pat[i] notin {'@', '#', '\''}: inc(i)
         else: break
       if i - 1 >= start:
-        add(result, substr(pat, start, i - 1))
+        result.add(substr(pat, start, i - 1))
 
 proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
   var op: TLoc
-  initLocExpr(p, ri.sons[0], op)
+  initLocExpr(p, ri[0], op)
   # getUniqueType() is too expensive here:
-  var typ = skipTypes(ri.sons[0].typ, abstractInst)
+  var typ = skipTypes(ri[0].typ, abstractInst)
   assert(typ.kind == tyProc)
-  var length = len(ri)
-  assert(len(typ) == len(typ.n))
+  assert(typ.len == typ.n.len)
   # don't call '$' here for efficiency:
-  let pat = ri.sons[0].sym.loc.r.data
+  let pat = ri[0].sym.loc.r.data
   internalAssert p.config, pat.len > 0
   if pat.contains({'#', '(', '@', '\''}):
     var pl = genPatternCall(p, ri, pat, typ)
     # simpler version of 'fixupCall' that works with the pl+params combination:
-    var typ = skipTypes(ri.sons[0].typ, abstractInst)
-    if typ.sons[0] != nil:
+    var typ = skipTypes(ri[0].typ, abstractInst)
+    if typ[0] != nil:
       if p.module.compileToCpp and lfSingleUse in d.flags:
         # do not generate spurious temporaries for C++! For C we're better off
         # with them to prevent undefined behaviour and because the codegen
@@ -469,115 +466,114 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
         d.r = pl
         excl d.flags, lfSingleUse
       else:
-        if d.k == locNone: getTemp(p, typ.sons[0], d)
+        if d.k == locNone: getTemp(p, typ[0], d)
         assert(d.t != nil)        # generate an assignment to d:
         var list: TLoc
         initLoc(list, locCall, d.lode, OnUnknown)
         list.r = pl
         genAssignment(p, d, list, {}) # no need for deep copying
     else:
-      add(pl, ~";$n")
+      pl.add(~";$n")
       line(p, cpsStmts, pl)
   else:
     var pl: Rope = nil
-    #var param = typ.n.sons[1].sym
+    #var param = typ.n[1].sym
     if 1 < ri.len:
-      add(pl, genThisArg(p, ri, 1, typ))
-    add(pl, op.r)
+      pl.add(genThisArg(p, ri, 1, typ))
+    pl.add(op.r)
     var params: Rope
-    for i in 2 ..< length:
+    for i in 2..<ri.len:
       if params != nil: params.add(~", ")
-      assert(len(typ) == len(typ.n))
-      add(params, genOtherArg(p, ri, i, typ))
+      assert(typ.len == typ.n.len)
+      params.add(genOtherArg(p, ri, i, typ))
     fixupCall(p, le, ri, d, pl, params)
 
 proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
   # generates a crappy ObjC call
   var op: TLoc
-  initLocExpr(p, ri.sons[0], op)
+  initLocExpr(p, ri[0], op)
   var pl = ~"["
   # getUniqueType() is too expensive here:
-  var typ = skipTypes(ri.sons[0].typ, abstractInst)
+  var typ = skipTypes(ri[0].typ, abstractInst)
   assert(typ.kind == tyProc)
-  var length = len(ri)
-  assert(len(typ) == len(typ.n))
+  assert(typ.len == typ.n.len)
 
   # don't call '$' here for efficiency:
-  let pat = ri.sons[0].sym.loc.r.data
+  let pat = ri[0].sym.loc.r.data
   internalAssert p.config, pat.len > 0
   var start = 3
   if ' ' in pat:
     start = 1
-    add(pl, op.r)
-    if length > 1:
-      add(pl, ~": ")
-      add(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
+    pl.add(op.r)
+    if ri.len > 1:
+      pl.add(~": ")
+      pl.add(genArg(p, ri[1], typ.n[1].sym, ri))
       start = 2
   else:
-    if length > 1:
-      add(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
-      add(pl, ~" ")
-    add(pl, op.r)
-    if length > 2:
-      add(pl, ~": ")
-      add(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri))
-  for i in start ..< length:
-    assert(len(typ) == len(typ.n))
-    if i >= len(typ):
+    if ri.len > 1:
+      pl.add(genArg(p, ri[1], typ.n[1].sym, ri))
+      pl.add(~" ")
+    pl.add(op.r)
+    if ri.len > 2:
+      pl.add(~": ")
+      pl.add(genArg(p, ri[2], typ.n[2].sym, ri))
+  for i in start..<ri.len:
+    assert(typ.len == typ.n.len)
+    if i >= typ.len:
       internalError(p.config, ri.info, "varargs for objective C method?")
-    assert(typ.n.sons[i].kind == nkSym)
-    var param = typ.n.sons[i].sym
-    add(pl, ~" ")
-    add(pl, param.name.s)
-    add(pl, ~": ")
-    add(pl, genArg(p, ri.sons[i], param, ri))
-  if typ.sons[0] != nil:
-    if isInvalidReturnType(p.config, typ.sons[0]):
-      if len(ri) > 1: add(pl, ~" ")
+    assert(typ.n[i].kind == nkSym)
+    var param = typ.n[i].sym
+    pl.add(~" ")
+    pl.add(param.name.s)
+    pl.add(~": ")
+    pl.add(genArg(p, ri[i], param, ri))
+  if typ[0] != nil:
+    if isInvalidReturnType(p.config, typ[0]):
+      if ri.len > 1: pl.add(~" ")
       # beware of 'result = p(result)'. We always allocate a temporary:
       if d.k in {locTemp, locNone}:
         # We already got a temp. Great, special case it:
-        if d.k == locNone: getTemp(p, typ.sons[0], d, needsInit=true)
-        add(pl, ~"Result: ")
-        add(pl, addrLoc(p.config, d))
-        add(pl, ~"];$n")
+        if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
+        pl.add(~"Result: ")
+        pl.add(addrLoc(p.config, d))
+        pl.add(~"];$n")
         line(p, cpsStmts, pl)
       else:
         var tmp: TLoc
-        getTemp(p, typ.sons[0], tmp, needsInit=true)
-        add(pl, addrLoc(p.config, tmp))
-        add(pl, ~"];$n")
+        getTemp(p, typ[0], tmp, needsInit=true)
+        pl.add(addrLoc(p.config, tmp))
+        pl.add(~"];$n")
         line(p, cpsStmts, pl)
         genAssignment(p, d, tmp, {}) # no need for deep copying
     else:
-      add(pl, ~"]")
-      if d.k == locNone: getTemp(p, typ.sons[0], d)
+      pl.add(~"]")
+      if d.k == locNone: getTemp(p, typ[0], d)
       assert(d.t != nil)        # generate an assignment to d:
       var list: TLoc
       initLoc(list, locCall, ri, OnUnknown)
       list.r = pl
       genAssignment(p, d, list, {}) # no need for deep copying
   else:
-    add(pl, ~"];$n")
+    pl.add(~"];$n")
     line(p, cpsStmts, pl)
 
 proc genCall(p: BProc, e: PNode, d: var TLoc) =
-  if e.sons[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure:
+  if e[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure:
     genClosureCall(p, nil, e, d)
-  elif e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags:
+  elif e[0].kind == nkSym and sfInfixCall in e[0].sym.flags:
     genInfixCall(p, nil, e, d)
-  elif e.sons[0].kind == nkSym and sfNamedParamCall in e.sons[0].sym.flags:
+  elif e[0].kind == nkSym and sfNamedParamCall in e[0].sym.flags:
     genNamedParamCall(p, e, d)
   else:
     genPrefixCall(p, nil, e, d)
   postStmtActions(p)
 
 proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
-  if ri.sons[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure:
+  if ri[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure:
     genClosureCall(p, le, ri, d)
-  elif ri.sons[0].kind == nkSym and sfInfixCall in ri.sons[0].sym.flags:
+  elif ri[0].kind == nkSym and sfInfixCall in ri[0].sym.flags:
     genInfixCall(p, le, ri, d)
-  elif ri.sons[0].kind == nkSym and sfNamedParamCall in ri.sons[0].sym.flags:
+  elif ri[0].kind == nkSym and sfNamedParamCall in ri[0].sym.flags:
     genNamedParamCall(p, ri, d)
   else:
     genPrefixCall(p, le, ri, d)
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 009ee7221..a95086c71 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -64,7 +64,7 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
       if id == p.module.labels:
         # not found in cache:
         inc(p.module.labels)
-        addf(p.module.s[cfsData],
+        p.module.s[cfsData].addf(
              "static NIM_CONST $1 $2 = {NIM_NIL,NIM_NIL};$n",
              [getTypeDesc(p.module, ty), result])
     else:
@@ -98,13 +98,13 @@ proc genLiteral(p: BProc, n: PNode): Rope =
 
 proc bitSetToWord(s: TBitSet, size: int): BiggestUInt =
   result = 0
-  for j in 0 ..< size:
-    if j < len(s): result = result or (BiggestUInt(s[j]) shl (j * 8))
+  for j in 0..<size:
+    if j < s.len: result = result or (BiggestUInt(s[j]) shl (j * 8))
 
 proc genRawSetData(cs: TBitSet, size: int): Rope =
   if size > 8:
     var res = "{\n"
-    for i in 0 ..< size:
+    for i in 0..<size:
       res.add "0x"
       res.add "0123456789abcdef"[cs[i] div 16]
       res.add "0123456789abcdef"[cs[i] mod 16]
@@ -131,7 +131,7 @@ proc genSetNode(p: BProc, n: PNode): Rope =
     if id == p.module.labels:
       # not found in cache:
       inc(p.module.labels)
-      addf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n",
+      p.module.s[cfsData].addf("static NIM_CONST $1 $2 = $3;$n",
            [getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)])
   else:
     result = genRawSetData(cs, size)
@@ -150,13 +150,13 @@ proc getStorageLoc(n: PNode): TStorageLoc =
       else: result = OnUnknown
     else: result = OnUnknown
   of nkDerefExpr, nkHiddenDeref:
-    case n.sons[0].typ.kind
+    case n[0].typ.kind
     of tyVar, tyLent: result = OnUnknown
     of tyPtr: result = OnStack
     of tyRef: result = OnHeap
     else: doAssert(false, "getStorageLoc")
   of nkBracketExpr, nkDotExpr, nkObjDownConv, nkObjUpConv:
-    result = getStorageLoc(n.sons[0])
+    result = getStorageLoc(n[0])
   else: result = OnUnknown
 
 proc canMove(p: BProc, n: PNode; dest: TLoc): bool =
@@ -217,8 +217,8 @@ proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
     else:
       flags
   let t = skipTypes(dest.t, abstractInst).getUniqueType()
-  for i in 0 ..< t.len:
-    let t = t.sons[i]
+  for i in 0..<t.len:
+    let t = t[i]
     let field = "Field$1" % [i.rope]
     genAssignment(p, optAsgnLoc(dest, t, field),
                      optAsgnLoc(src, t, field), newflags)
@@ -327,7 +327,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
     elif not isObjLackingTypeField(ty):
       genGenericAsgn(p, dest, src, flags)
     elif containsGarbageCollectedRef(ty):
-      if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4:
+      if ty[0].isNil and asgnComplexity(ty.n) <= 4:
         discard getTypeDesc(p.module, ty)
         internalAssert p.config, ty.n != nil
         genOptAsgnObject(p, dest, src, flags, ty.n, ty)
@@ -452,47 +452,47 @@ proc putIntoDest(p: BProc, d: var TLoc, n: PNode, r: Rope; s=OnUnknown) =
 proc binaryStmt(p: BProc, e: PNode, d: var TLoc, op: string) =
   var a, b: TLoc
   if d.k != locNone: internalError(p.config, e.info, "binaryStmt")
-  initLocExpr(p, e.sons[1], a)
-  initLocExpr(p, e.sons[2], b)
+  initLocExpr(p, e[1], a)
+  initLocExpr(p, e[2], b)
   lineCg(p, cpsStmts, "$1 $2 $3;$n", [rdLoc(a), op, rdLoc(b)])
 
 proc binaryStmtAddr(p: BProc, e: PNode, d: var TLoc, cpname: string) =
   var a, b: TLoc
   if d.k != locNone: internalError(p.config, e.info, "binaryStmtAddr")
-  initLocExpr(p, e.sons[1], a)
-  initLocExpr(p, e.sons[2], b)
+  initLocExpr(p, e[1], a)
+  initLocExpr(p, e[2], b)
   lineCg(p, cpsStmts, "#$1($2, $3);$n", [cpname, byRefLoc(p, a), rdLoc(b)])
 
 template unaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
   var a: TLoc
   if d.k != locNone: internalError(p.config, e.info, "unaryStmt")
-  initLocExpr(p, e.sons[1], a)
+  initLocExpr(p, e[1], a)
   lineCg(p, cpsStmts, frmt, [rdLoc(a)])
 
 template binaryExpr(p: BProc, e: PNode, d: var TLoc, frmt: string) =
   var a, b: TLoc
-  assert(e.sons[1].typ != nil)
-  assert(e.sons[2].typ != nil)
-  initLocExpr(p, e.sons[1], a)
-  initLocExpr(p, e.sons[2], b)
+  assert(e[1].typ != nil)
+  assert(e[2].typ != nil)
+  initLocExpr(p, e[1], a)
+  initLocExpr(p, e[2], b)
   putIntoDest(p, d, e, ropecg(p.module, frmt, [rdLoc(a), rdLoc(b)]))
 
 template binaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: string) =
   var a, b: TLoc
-  assert(e.sons[1].typ != nil)
-  assert(e.sons[2].typ != nil)
-  initLocExpr(p, e.sons[1], a)
-  initLocExpr(p, e.sons[2], b)
+  assert(e[1].typ != nil)
+  assert(e[2].typ != nil)
+  initLocExpr(p, e[1], a)
+  initLocExpr(p, e[2], b)
   putIntoDest(p, d, e, ropecg(p.module, frmt, [a.rdCharLoc, b.rdCharLoc]))
 
 template unaryExpr(p: BProc, e: PNode, d: var TLoc, frmt: string) =
   var a: TLoc
-  initLocExpr(p, e.sons[1], a)
+  initLocExpr(p, e[1], a)
   putIntoDest(p, d, e, ropecg(p.module, frmt, [rdLoc(a)]))
 
 template unaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: string) =
   var a: TLoc
-  initLocExpr(p, e.sons[1], a)
+  initLocExpr(p, e[1], a)
   putIntoDest(p, d, e, ropecg(p.module, frmt, [rdCharLoc(a)]))
 
 template binaryArithOverflowRaw(p: BProc, t: PType, a, b: TLoc;
@@ -522,10 +522,10 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
     ]
     opr: array[mAddI..mPred, string] = ["+", "-", "*", "/", "%", "+", "-"]
   var a, b: TLoc
-  assert(e.sons[1].typ != nil)
-  assert(e.sons[2].typ != nil)
-  initLocExpr(p, e.sons[1], a)
-  initLocExpr(p, e.sons[2], b)
+  assert(e[1].typ != nil)
+  assert(e[2].typ != nil)
+  initLocExpr(p, e[1], a)
+  initLocExpr(p, e[2], b)
   # skipping 'range' is correct here as we'll generate a proper range check
   # later via 'chckRange'
   let t = e.typ.skipTypes(abstractRange)
@@ -541,8 +541,8 @@ proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
   var
     a: TLoc
     t: PType
-  assert(e.sons[1].typ != nil)
-  initLocExpr(p, e.sons[1], a)
+  assert(e[1].typ != nil)
+  initLocExpr(p, e[1], a)
   t = skipTypes(e.typ, abstractRange)
   if optOverflowCheck in p.options:
     linefmt(p, cpsStmts, "if ($1 == $2) #raiseOverflow();$n",
@@ -561,10 +561,10 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   var
     a, b: TLoc
     s, k: BiggestInt
-  assert(e.sons[1].typ != nil)
-  assert(e.sons[2].typ != nil)
-  initLocExpr(p, e.sons[1], a)
-  initLocExpr(p, e.sons[2], b)
+  assert(e[1].typ != nil)
+  assert(e[2].typ != nil)
+  initLocExpr(p, e[1], a)
+  initLocExpr(p, e[2], b)
   # BUGFIX: cannot use result-type here, as it may be a boolean
   s = max(getSize(p.config, a.t), getSize(p.config, b.t)) * 8
   k = getSize(p.config, a.t) * 8
@@ -622,10 +622,10 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
 
 proc genEqProc(p: BProc, e: PNode, d: var TLoc) =
   var a, b: TLoc
-  assert(e.sons[1].typ != nil)
-  assert(e.sons[2].typ != nil)
-  initLocExpr(p, e.sons[1], a)
-  initLocExpr(p, e.sons[2], b)
+  assert(e[1].typ != nil)
+  assert(e[2].typ != nil)
+  initLocExpr(p, e[1], a)
+  initLocExpr(p, e[2], b)
   if a.t.skipTypes(abstractInstOwned).callConv == ccClosure:
     putIntoDest(p, d, e,
       "($1.ClP_0 == $2.ClP_0 && $1.ClE_0 == $2.ClE_0)" % [rdLoc(a), rdLoc(b)])
@@ -633,7 +633,7 @@ proc genEqProc(p: BProc, e: PNode, d: var TLoc) =
     putIntoDest(p, d, e, "($1 == $2)" % [rdLoc(a), rdLoc(b)])
 
 proc genIsNil(p: BProc, e: PNode, d: var TLoc) =
-  let t = skipTypes(e.sons[1].typ, abstractRange)
+  let t = skipTypes(e[1].typ, abstractRange)
   if t.kind == tyProc and t.callConv == ccClosure:
     unaryExpr(p, e, d, "($1.ClP_0 == 0)")
   else:
@@ -643,8 +643,8 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   var
     a: TLoc
     t: PType
-  assert(e.sons[1].typ != nil)
-  initLocExpr(p, e.sons[1], a)
+  assert(e[1].typ != nil)
+  initLocExpr(p, e[1], a)
   t = skipTypes(e.typ, abstractRange)
 
   template applyFormat(frmt: untyped) =
@@ -670,24 +670,24 @@ proc isCppRef(p: BProc; typ: PType): bool {.inline.} =
       tfVarIsPtr notin skipTypes(typ, abstractInstOwned).flags
 
 proc genDeref(p: BProc, e: PNode, d: var TLoc) =
-  let mt = mapType(p.config, e.sons[0].typ)
+  let mt = mapType(p.config, e[0].typ)
   if mt in {ctArray, ctPtrToArray} and lfEnforceDeref notin d.flags:
     # XXX the amount of hacks for C's arrays is incredible, maybe we should
     # simply wrap them in a struct? --> Losing auto vectorization then?
-    expr(p, e.sons[0], d)
-    if e.sons[0].typ.skipTypes(abstractInstOwned).kind == tyRef:
+    expr(p, e[0], d)
+    if e[0].typ.skipTypes(abstractInstOwned).kind == tyRef:
       d.storage = OnHeap
   else:
     var a: TLoc
-    var typ = e.sons[0].typ
+    var typ = e[0].typ
     if typ.kind in {tyUserTypeClass, tyUserTypeClassInst} and typ.isResolvedUserTypeClass:
       typ = typ.lastSon
     typ = typ.skipTypes(abstractInstOwned)
-    if typ.kind == tyVar and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e.sons[0].kind == nkHiddenAddr:
+    if typ.kind == tyVar and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e[0].kind == nkHiddenAddr:
       initLocExprSingleUse(p, e[0][0], d)
       return
     else:
-      initLocExprSingleUse(p, e.sons[0], a)
+      initLocExprSingleUse(p, e[0], a)
     if d.k == locNone:
       # dest = *a;  <-- We do not know that 'dest' is on the heap!
       # It is completely wrong to set 'd.storage' here, unless it's not yet
@@ -716,30 +716,30 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) =
       # See tmissingderef. So we get rid of the deref instead. The codegen
       # ends up using 'memcpy' for the array assignment,
       # so the '&' and '*' cancel out:
-      putIntoDest(p, d, lodeTyp(a.t.sons[0]), rdLoc(a), a.storage)
+      putIntoDest(p, d, lodeTyp(a.t[0]), rdLoc(a), a.storage)
     else:
       putIntoDest(p, d, e, "(*$1)" % [rdLoc(a)], a.storage)
 
 proc genAddr(p: BProc, e: PNode, d: var TLoc) =
   # careful  'addr(myptrToArray)' needs to get the ampersand:
-  if e.sons[0].typ.skipTypes(abstractInstOwned).kind in {tyRef, tyPtr}:
+  if e[0].typ.skipTypes(abstractInstOwned).kind in {tyRef, tyPtr}:
     var a: TLoc
-    initLocExpr(p, e.sons[0], a)
+    initLocExpr(p, e[0], a)
     putIntoDest(p, d, e, "&" & a.r, a.storage)
     #Message(e.info, warnUser, "HERE NEW &")
-  elif mapType(p.config, e.sons[0].typ) == ctArray or isCppRef(p, e.typ):
-    expr(p, e.sons[0], d)
+  elif mapType(p.config, e[0].typ) == ctArray or isCppRef(p, e.typ):
+    expr(p, e[0], d)
   else:
     var a: TLoc
-    initLocExpr(p, e.sons[0], a)
+    initLocExpr(p, e[0], a)
     putIntoDest(p, d, e, addrLoc(p.config, a), a.storage)
 
 template inheritLocation(d: var TLoc, a: TLoc) =
   if d.k == locNone: d.storage = a.storage
 
 proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc) =
-  initLocExpr(p, e.sons[0], a)
-  if e.sons[1].kind != nkSym: internalError(p.config, e.info, "genRecordFieldAux")
+  initLocExpr(p, e[0], a)
+  if e[1].kind != nkSym: internalError(p.config, e.info, "genRecordFieldAux")
   d.inheritLocation(a)
   discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
 
@@ -747,16 +747,16 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
   var
     a: TLoc
     i: int
-  initLocExpr(p, e.sons[0], a)
+  initLocExpr(p, e[0], a)
   let tupType = a.t.skipTypes(abstractInst+{tyVar})
   assert tupType.kind == tyTuple
   d.inheritLocation(a)
   discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
   var r = rdLoc(a)
-  case e.sons[1].kind
-  of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal)
+  case e[1].kind
+  of nkIntLit..nkUInt64Lit: i = int(e[1].intVal)
   else: internalError(p.config, e.info, "genTupleElem")
-  addf(r, ".Field$1", [rope(i)])
+  r.addf(".Field$1", [rope(i)])
   putIntoDest(p, d, e, r, a.storage)
 
 proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope;
@@ -770,43 +770,43 @@ proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope;
     if result != nil:
       if resTyp != nil: resTyp[] = ty
       break
-    if not p.module.compileToCpp: add(r, ".Sup")
-    ty = ty.sons[0]
+    if not p.module.compileToCpp: r.add(".Sup")
+    ty = ty[0]
   if result == nil: internalError(p.config, field.info, "genCheckedRecordField")
 
 proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
   var a: TLoc
   genRecordFieldAux(p, e, d, a)
   var r = rdLoc(a)
-  var f = e.sons[1].sym
+  var f = e[1].sym
   let ty = skipTypes(a.t, abstractInstOwned + tyUserTypeClasses)
   if ty.kind == tyTuple:
     # we found a unique tuple type which lacks field information
     # so we use Field$i
-    addf(r, ".Field$1", [rope(f.position)])
+    r.addf(".Field$1", [rope(f.position)])
     putIntoDest(p, d, e, r, a.storage)
   else:
     var rtyp: PType
     let field = lookupFieldAgain(p, ty, f, r, addr rtyp)
     if field.loc.r == nil and rtyp != nil: fillObjectFields(p.module, rtyp)
     if field.loc.r == nil: internalError(p.config, e.info, "genRecordField 3 " & typeToString(ty))
-    addf(r, ".$1", [field.loc.r])
+    r.addf(".$1", [field.loc.r])
     putIntoDest(p, d, e, r, a.storage)
 
 proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc)
 
 proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
   var test, u, v: TLoc
-  for i in 1 ..< len(e):
-    var it = e.sons[i]
+  for i in 1..<e.len:
+    var it = e[i]
     assert(it.kind in nkCallKinds)
-    assert(it.sons[0].kind == nkSym)
-    let op = it.sons[0].sym
-    if op.magic == mNot: it = it.sons[1]
-    let disc = it.sons[2].skipConv
+    assert(it[0].kind == nkSym)
+    let op = it[0].sym
+    if op.magic == mNot: it = it[1]
+    let disc = it[2].skipConv
     assert(disc.kind == nkSym)
     initLoc(test, locNone, it, OnStack)
-    initLocExpr(p, it.sons[1], u)
+    initLocExpr(p, it[1], u)
     initLoc(v, locExpr, disc, OnUnknown)
     v.r = obj
     v.r.add(".")
@@ -826,19 +826,19 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
 proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
   if optFieldCheck in p.options:
     var a: TLoc
-    genRecordFieldAux(p, e.sons[0], d, a)
+    genRecordFieldAux(p, e[0], d, a)
     let ty = skipTypes(a.t, abstractInst + tyUserTypeClasses)
     var r = rdLoc(a)
-    let f = e.sons[0].sons[1].sym
+    let f = e[0][1].sym
     let field = lookupFieldAgain(p, ty, f, r)
     if field.loc.r == nil: fillObjectFields(p.module, ty)
     if field.loc.r == nil:
       internalError(p.config, e.info, "genCheckedRecordField") # generate the checks:
     genFieldCheck(p, e, r, field)
-    add(r, ropecg(p.module, ".$1", [field.loc.r]))
-    putIntoDest(p, d, e.sons[0], r, a.storage)
+    r.add(ropecg(p.module, ".$1", [field.loc.r]))
+    putIntoDest(p, d, e[0], r, a.storage)
   else:
-    genRecordField(p, e.sons[0], d)
+    genRecordField(p, e[0], d)
 
 proc genUncheckedArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
   var a, b: TLoc
@@ -940,14 +940,14 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
               ropecg(p.module, "$1$3[$2]", [rdLoc(a), rdCharLoc(b), dataField(p)]), a.storage)
 
 proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
-  var ty = skipTypes(n.sons[0].typ, abstractVarRange + tyUserTypeClasses)
+  var ty = skipTypes(n[0].typ, abstractVarRange + tyUserTypeClasses)
   if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
   case ty.kind
-  of tyUncheckedArray: genUncheckedArrayElem(p, n, n.sons[0], n.sons[1], d)
-  of tyArray: genArrayElem(p, n, n.sons[0], n.sons[1], d)
-  of tyOpenArray, tyVarargs: genOpenArrayElem(p, n, n.sons[0], n.sons[1], d)
-  of tySequence, tyString: genSeqElem(p, n, n.sons[0], n.sons[1], d)
-  of tyCString: genCStringElem(p, n, n.sons[0], n.sons[1], d)
+  of tyUncheckedArray: genUncheckedArrayElem(p, n, n[0], n[1], d)
+  of tyArray: genArrayElem(p, n, n[0], n[1], d)
+  of tyOpenArray, tyVarargs: genOpenArrayElem(p, n, n[0], n[1], d)
+  of tySequence, tyString: genSeqElem(p, n, n[0], n[1], d)
+  of tyCString: genCStringElem(p, n, n[0], n[1], d)
   of tyTuple: genTupleElem(p, n, d)
   else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
   discard getTypeDesc(p.module, n.typ)
@@ -962,7 +962,7 @@ proc isSimpleExpr(n: PNode): bool =
       if not isSimpleExpr(c): return false
     result = true
   of nkStmtListExpr:
-    for i in 0..n.len-2:
+    for i in 0..<n.len-1:
       if n[i].kind notin {nkCommentStmt, nkEmpty}: return false
     result = isSimpleExpr(n.lastSon)
   else:
@@ -995,8 +995,8 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
     var tmpA, tmpB: TLoc
     #getTemp(p, e.typ, tmpA)
     #getTemp(p, e.typ, tmpB)
-    initLocExprSingleUse(p, e.sons[1], tmpA)
-    initLocExprSingleUse(p, e.sons[2], tmpB)
+    initLocExprSingleUse(p, e[1], tmpA)
+    initLocExprSingleUse(p, e[2], tmpB)
     tmpB.k = locExpr
     if m == mOr:
       tmpB.r = "((" & rdLoc(tmpA) & ")||(" & rdLoc(tmpB) & "))"
@@ -1012,13 +1012,13 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
       tmp: TLoc
     getTemp(p, e.typ, tmp)      # force it into a temp!
     inc p.splitDecls
-    expr(p, e.sons[1], tmp)
+    expr(p, e[1], tmp)
     L = getLabel(p)
     if m == mOr:
       lineF(p, cpsStmts, "if ($1) goto $2;$n", [rdLoc(tmp), L])
     else:
       lineF(p, cpsStmts, "if (!($1)) goto $2;$n", [rdLoc(tmp), L])
-    expr(p, e.sons[2], tmp)
+    expr(p, e[2], tmp)
     fixLabel(p, L)
     if d.k == locNone:
       d = tmp
@@ -1036,10 +1036,10 @@ proc genEcho(p: BProc, n: PNode) =
     var a: TLoc
     for it in n.sons:
       if it.skipConv.kind == nkNilLit:
-        add(args, ", \"\"")
+        args.add(", \"\"")
       else:
         initLocExpr(p, it, a)
-        add(args, ropecg(p.module, ", Genode::Cstring($1->data, $1->len)", [rdLoc(a)]))
+        args.add(ropecg(p.module, ", Genode::Cstring($1->data, $1->len)", [rdLoc(a)]))
     p.module.includeHeader("<base/log.h>")
     p.module.includeHeader("<util/string.h>")
     linefmt(p, cpsStmts, """Genode::log(""$1);$n""", [args])
@@ -1087,21 +1087,21 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
   var L = 0
   var appends: Rope = nil
   var lens: Rope = nil
-  for i in 0 .. len(e) - 2:
+  for i in 0..<e.len - 1:
     # compute the length expression:
-    initLocExpr(p, e.sons[i + 1], a)
-    if skipTypes(e.sons[i + 1].typ, abstractVarRange).kind == tyChar:
+    initLocExpr(p, e[i + 1], a)
+    if skipTypes(e[i + 1].typ, abstractVarRange).kind == tyChar:
       inc(L)
-      add(appends, ropecg(p.module, "#appendChar($1, $2);$n", [strLoc(p, tmp), rdLoc(a)]))
+      appends.add(ropecg(p.module, "#appendChar($1, $2);$n", [strLoc(p, tmp), rdLoc(a)]))
     else:
-      if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
-        inc(L, len(e.sons[i + 1].strVal))
+      if e[i + 1].kind in {nkStrLit..nkTripleStrLit}:
+        inc(L, e[i + 1].strVal.len)
       else:
-        add(lens, lenExpr(p, a))
-        add(lens, " + ")
-      add(appends, ropecg(p.module, "#appendString($1, $2);$n", [strLoc(p, tmp), rdLoc(a)]))
+        lens.add(lenExpr(p, a))
+        lens.add(" + ")
+      appends.add(ropecg(p.module, "#appendString($1, $2);$n", [strLoc(p, tmp), rdLoc(a)]))
   linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", [tmp.r, lens, L])
-  add(p.s(cpsStmts), appends)
+  p.s(cpsStmts).add appends
   if d.k == locNone:
     d = tmp
   else:
@@ -1125,21 +1125,21 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
     appends, lens: Rope
   assert(d.k == locNone)
   var L = 0
-  initLocExpr(p, e.sons[1], dest)
-  for i in 0 .. len(e) - 3:
+  initLocExpr(p, e[1], dest)
+  for i in 0..<e.len - 2:
     # compute the length expression:
-    initLocExpr(p, e.sons[i + 2], a)
-    if skipTypes(e.sons[i + 2].typ, abstractVarRange).kind == tyChar:
+    initLocExpr(p, e[i + 2], a)
+    if skipTypes(e[i + 2].typ, abstractVarRange).kind == tyChar:
       inc(L)
-      add(appends, ropecg(p.module, "#appendChar($1, $2);$n",
+      appends.add(ropecg(p.module, "#appendChar($1, $2);$n",
                         [strLoc(p, dest), rdLoc(a)]))
     else:
-      if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
-        inc(L, len(e.sons[i + 2].strVal))
+      if e[i + 2].kind in {nkStrLit..nkTripleStrLit}:
+        inc(L, e[i + 2].strVal.len)
       else:
-        add(lens, lenExpr(p, a))
-        add(lens, " + ")
-      add(appends, ropecg(p.module, "#appendString($1, $2);$n",
+        lens.add(lenExpr(p, a))
+        lens.add(" + ")
+      appends.add(ropecg(p.module, "#appendString($1, $2);$n",
                         [strLoc(p, dest), rdLoc(a)]))
   if optSeqDestructors in p.config.globalOptions:
     linefmt(p, cpsStmts, "#prepareAdd($1, $2$3);$n",
@@ -1149,33 +1149,33 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
     call.r = ropecg(p.module, "#resizeString($1, $2$3)", [rdLoc(dest), lens, L])
     genAssignment(p, dest, call, {})
     gcUsage(p.config, e)
-  add(p.s(cpsStmts), appends)
+  p.s(cpsStmts).add appends
 
 proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
   # seq &= x  -->
   #    seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x));
   #    seq->data[seq->len-1] = x;
   var a, b, dest, tmpL, call: TLoc
-  initLocExpr(p, e.sons[1], a)
-  initLocExpr(p, e.sons[2], b)
-  let seqType = skipTypes(e.sons[1].typ, {tyVar})
+  initLocExpr(p, e[1], a)
+  initLocExpr(p, e[2], b)
+  let seqType = skipTypes(e[1].typ, {tyVar})
   initLoc(call, locCall, e, OnHeap)
   if not p.module.compileToCpp:
     const seqAppendPattern = "($2) #incrSeqV3((TGenericSeq*)($1), $3)"
     call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a),
-      getTypeDesc(p.module, e.sons[1].typ),
+      getTypeDesc(p.module, e[1].typ),
       genTypeInfo(p.module, seqType, e.info)])
   else:
     const seqAppendPattern = "($2) #incrSeqV3($1, $3)"
     call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a),
-      getTypeDesc(p.module, e.sons[1].typ),
+      getTypeDesc(p.module, e[1].typ),
       genTypeInfo(p.module, seqType, e.info)])
   # emit the write barrier if required, but we can always move here, so
   # use 'genRefAssign' for the seq.
   genRefAssign(p, a, call)
   #if bt != b.t:
   #  echo "YES ", e.info, " new: ", typeToString(bt), " old: ", typeToString(b.t)
-  initLoc(dest, locExpr, e.sons[2], OnHeap)
+  initLoc(dest, locExpr, e[2], OnHeap)
   getIntTemp(p, tmpL)
   lineCg(p, cpsStmts, "$1 = $2->$3++;$n", [tmpL.r, rdLoc(a), lenField(p)])
   dest.r = ropecg(p.module, "$1$3[$2]", [rdLoc(a), tmpL.r, dataField(p)])
@@ -1184,7 +1184,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
 
 proc genReset(p: BProc, n: PNode) =
   var a: TLoc
-  initLocExpr(p, n.sons[1], a)
+  initLocExpr(p, n[1], a)
   linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
           [addrLoc(p.config, a),
           genTypeInfo(p.module, skipTypes(a.t, {tyVar}), n.info)])
@@ -1220,7 +1220,7 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
           "to have the 'nimcall' calling convention")
       var f: TLoc
       initLocExpr(p, newSymNode(bt.destructor), f)
-      addf(p.module.s[cfsTypeInit3], "$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
+      p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
 
     if a.storage == OnHeap and usesWriteBarrier(p.config):
       if canFormAcycle(a.t):
@@ -1245,11 +1245,11 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
 
 proc genNew(p: BProc, e: PNode) =
   var a: TLoc
-  initLocExpr(p, e.sons[1], a)
+  initLocExpr(p, e[1], a)
   # 'genNew' also handles 'unsafeNew':
   if e.len == 3:
     var se: TLoc
-    initLocExpr(p, e.sons[2], se)
+    initLocExpr(p, e[2], se)
     rawGenNew(p, a, se.rdLoc)
   else:
     rawGenNew(p, a, nil)
@@ -1284,10 +1284,10 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) =
 
 proc genNewSeq(p: BProc, e: PNode) =
   var a, b: TLoc
-  initLocExpr(p, e.sons[1], a)
-  initLocExpr(p, e.sons[2], b)
+  initLocExpr(p, e[1], a)
+  initLocExpr(p, e[2], b)
   if optSeqDestructors in p.config.globalOptions:
-    let seqtype = skipTypes(e.sons[1].typ, abstractVarRange)
+    let seqtype = skipTypes(e[1].typ, abstractVarRange)
     linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
       [a.rdLoc, b.rdLoc, getTypeDesc(p.module, seqtype.lastSon),
       getSeqPayloadType(p.module, seqtype)])
@@ -1300,7 +1300,7 @@ proc genNewSeq(p: BProc, e: PNode) =
 proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
   let seqtype = skipTypes(e.typ, abstractVarRange)
   var a: TLoc
-  initLocExpr(p, e.sons[1], a)
+  initLocExpr(p, e[1], a)
   if optSeqDestructors in p.config.globalOptions:
     if d.k == locNone: getTemp(p, e.typ, d, needsInit=false)
     linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
@@ -1323,7 +1323,7 @@ proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
     if id == p.module.labels:
       # expression not found in the cache:
       inc(p.module.labels)
-      addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
+      p.module.s[cfsData].addf("NIM_CONST $1 $2 = $3;$n",
            [getTypeDesc(p.module, t), d.r, genConstExpr(p, n)])
     result = true
   else:
@@ -1361,25 +1361,25 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
     r = rdLoc(d)
   discard getTypeDesc(p.module, t)
   let ty = getUniqueType(t)
-  for i in 1 ..< e.len:
-    let it = e.sons[i]
+  for i in 1..<e.len:
+    let it = e[i]
     var tmp2: TLoc
     tmp2.r = r
-    let field = lookupFieldAgain(p, ty, it.sons[0].sym, tmp2.r)
+    let field = lookupFieldAgain(p, ty, it[0].sym, tmp2.r)
     if field.loc.r == nil: fillObjectFields(p.module, ty)
     if field.loc.r == nil: internalError(p.config, e.info, "genObjConstr")
     if it.len == 3 and optFieldCheck in p.options:
-      genFieldCheck(p, it.sons[2], r, field)
-    add(tmp2.r, ".")
-    add(tmp2.r, field.loc.r)
+      genFieldCheck(p, it[2], r, field)
+    tmp2.r.add(".")
+    tmp2.r.add(field.loc.r)
     if useTemp:
       tmp2.k = locTemp
       tmp2.storage = if isRef: OnHeap else: OnStack
     else:
       tmp2.k = d.k
       tmp2.storage = if isRef: OnHeap else: d.storage
-    tmp2.lode = it.sons[1]
-    expr(p, it.sons[1], tmp2)
+    tmp2.lode = it[1]
+    expr(p, it[1], tmp2)
   if useTemp:
     if d.k == locNone:
       d = tmp
@@ -1400,7 +1400,7 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
   elif d.k == locNone:
     getTemp(p, n.typ, d)
 
-  let l = intLiteral(len(n))
+  let l = intLiteral(n.len)
   if optSeqDestructors in p.config.globalOptions:
     let seqtype = n.typ
     linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
@@ -1410,7 +1410,7 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
     # generate call to newSeq before adding the elements per hand:
     genNewSeqAux(p, dest[], l,
       optNilSeqs notin p.options and n.len == 0)
-  for i in 0 ..< len(n):
+  for i in 0..<n.len:
     initLoc(arr, locExpr, n[i], OnHeap)
     arr.r = ropecg(p.module, "$1$3[$2]", [rdLoc(dest[]), intLiteral(i), dataField(p)])
     arr.storage = OnHeap            # we know that sequences are on the heap
@@ -1424,14 +1424,14 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
 
 proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
   var elem, a, arr: TLoc
-  if n.sons[1].kind == nkBracket:
-    n.sons[1].typ = n.typ
-    genSeqConstr(p, n.sons[1], d)
+  if n[1].kind == nkBracket:
+    n[1].typ = n.typ
+    genSeqConstr(p, n[1], d)
     return
   if d.k == locNone:
     getTemp(p, n.typ, d)
   # generate call to newSeq before adding the elements per hand:
-  let L = toInt(lengthOrd(p.config, n.sons[1].typ))
+  let L = toInt(lengthOrd(p.config, n[1].typ))
   if optSeqDestructors in p.config.globalOptions:
     let seqtype = n.typ
     linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
@@ -1439,14 +1439,14 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
       getSeqPayloadType(p.module, seqtype)])
   else:
     genNewSeqAux(p, d, intLiteral(L), optNilSeqs notin p.options and L == 0)
-  initLocExpr(p, n.sons[1], a)
+  initLocExpr(p, n[1], a)
   # bug #5007; do not produce excessive C source code:
   if L < 10:
-    for i in 0 ..< L:
+    for i in 0..<L:
       initLoc(elem, locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap)
       elem.r = ropecg(p.module, "$1$3[$2]", [rdLoc(d), intLiteral(i), dataField(p)])
       elem.storage = OnHeap # we know that sequences are on the heap
-      initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.sons[1].typ, abstractInst)), a.storage)
+      initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n[1].typ, abstractInst)), a.storage)
       arr.r = ropecg(p.module, "$1[$2]", [rdLoc(a), intLiteral(i)])
       genAssignment(p, elem, arr, {needToCopy})
   else:
@@ -1456,7 +1456,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
     initLoc(elem, locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap)
     elem.r = ropecg(p.module, "$1$3[$2]", [rdLoc(d), rdLoc(i), dataField(p)])
     elem.storage = OnHeap # we know that sequences are on the heap
-    initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.sons[1].typ, abstractInst)), a.storage)
+    initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n[1].typ, abstractInst)), a.storage)
     arr.r = ropecg(p.module, "$1[$2]", [rdLoc(a), rdLoc(i)])
     genAssignment(p, elem, arr, {needToCopy})
     lineF(p, cpsStmts, "}$n", [])
@@ -1467,12 +1467,12 @@ proc genNewFinalize(p: BProc, e: PNode) =
     a, b, f: TLoc
     refType, bt: PType
     ti: Rope
-  refType = skipTypes(e.sons[1].typ, abstractVarRange)
-  initLocExpr(p, e.sons[1], a)
-  initLocExpr(p, e.sons[2], f)
+  refType = skipTypes(e[1].typ, abstractVarRange)
+  initLocExpr(p, e[1], a)
+  initLocExpr(p, e[2], f)
   initLoc(b, locExpr, a.lode, OnHeap)
   ti = genTypeInfo(p.module, refType, e.info)
-  addf(p.module.s[cfsTypeInit3], "$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
+  p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
   b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [
       getTypeDesc(p.module, refType),
       ti, getTypeDesc(p.module, skipTypes(refType.lastSon, abstractRange))])
@@ -1496,7 +1496,7 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope =
       discard cgsym(p.module, "TNimType")
       inc p.module.labels
       let cache = "Nim_OfCheck_CACHE" & p.module.labels.rope
-      addf(p.module.s[cfsVars], "static TNimType* $#[2];$n", [cache])
+      p.module.s[cfsVars].addf("static TNimType* $#[2];$n", [cache])
       result = ropecg(p.module, "#isObjWithCache($#.m_type, $#, $#)", [a, ti, cache])
     when false:
       # former version:
@@ -1517,9 +1517,9 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
     t = skipTypes(t.lastSon, typedescInst+{tyOwned})
   discard getTypeDesc(p.module, t)
   if not p.module.compileToCpp:
-    while t.kind == tyObject and t.sons[0] != nil:
-      add(r, ~".Sup")
-      t = skipTypes(t.sons[0], skipPtrs)
+    while t.kind == tyObject and t[0] != nil:
+      r.add(~".Sup")
+      t = skipTypes(t[0], skipPtrs)
   if isObjLackingTypeField(t):
     globalError(p.config, x.info,
       "no 'of' operator available for pure objects")
@@ -1530,14 +1530,14 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
   putIntoDest(p, d, x, r, a.storage)
 
 proc genOf(p: BProc, n: PNode, d: var TLoc) =
-  genOf(p, n.sons[1], n.sons[2].typ, d)
+  genOf(p, n[1], n[2].typ, d)
 
 proc genRepr(p: BProc, e: PNode, d: var TLoc) =
   if optTinyRtti in p.config.globalOptions:
     localError(p.config, e.info, "'repr' is not available for --newruntime")
   var a: TLoc
-  initLocExpr(p, e.sons[1], a)
-  var t = skipTypes(e.sons[1].typ, abstractVarRange)
+  initLocExpr(p, e[1], a)
+  var t = skipTypes(e[1].typ, abstractVarRange)
   case t.kind
   of tyInt..tyInt64, tyUInt..tyUInt64:
     putIntoDest(p, d, e,
@@ -1568,7 +1568,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
     of tyArray:
       putIntoDest(p, b, e,
                   "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))], a.storage)
-    else: internalError(p.config, e.sons[0].info, "genRepr()")
+    else: internalError(p.config, e[0].info, "genRepr()")
     putIntoDest(p, d, e,
         ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b),
         genTypeInfo(p.module, elemType(t), e.info)]), a.storage)
@@ -1585,12 +1585,12 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
   gcUsage(p.config, e)
 
 proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) =
-  let t = e.sons[1].typ
+  let t = e[1].typ
   putIntoDest(p, d, e, genTypeInfo(p.module, t, e.info))
 
 template genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
   var a: TLoc
-  initLocExpr(p, n.sons[1], a)
+  initLocExpr(p, n[1], a)
   a.r = ropecg(p.module, frmt, [rdLoc(a)])
   a.flags = a.flags - {lfIndirect} # this flag should not be propagated here (not just for HCR)
   if d.k == locNone: getTemp(p, n.typ, d)
@@ -1598,8 +1598,8 @@ template genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
   gcUsage(p.config, n)
 
 proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
-  var a = e.sons[1]
-  if a.kind == nkHiddenAddr: a = a.sons[0]
+  var a = e[1]
+  if a.kind == nkHiddenAddr: a = a[0]
   var typ = skipTypes(a.typ, abstractVar + tyUserTypeClasses)
   case typ.kind
   of tyOpenArray, tyVarargs:
@@ -1621,7 +1621,7 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)")
   of tyString:
     var a: TLoc
-    initLocExpr(p, e.sons[1], a)
+    initLocExpr(p, e[1], a)
     var x = lenExpr(p, a)
     if op == mHigh: x = "($1-1)" % [x]
     putIntoDest(p, d, e, x)
@@ -1653,16 +1653,16 @@ proc makeAddr(n: PNode): PNode =
 
 proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
   if optSeqDestructors in p.config.globalOptions:
-    e.sons[1] = makeAddr(e[1])
+    e[1] = makeAddr(e[1])
     genCall(p, e, d)
     return
   var a, b, call: TLoc
   assert(d.k == locNone)
-  var x = e.sons[1]
+  var x = e[1]
   if x.kind in {nkAddr, nkHiddenAddr}: x = x[0]
   initLocExpr(p, x, a)
-  initLocExpr(p, e.sons[2], b)
-  let t = skipTypes(e.sons[1].typ, {tyVar})
+  initLocExpr(p, e[2], b)
+  let t = skipTypes(e[1].typ, {tyVar})
 
   initLoc(call, locCall, e, OnHeap)
   if not p.module.compileToCpp:
@@ -1686,8 +1686,8 @@ proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) =
   else:
     var a, b, call: TLoc
     if d.k != locNone: internalError(p.config, e.info, "genSetLengthStr")
-    initLocExpr(p, e.sons[1], a)
-    initLocExpr(p, e.sons[2], b)
+    initLocExpr(p, e[1], a)
+    initLocExpr(p, e[2], b)
 
     initLoc(call, locCall, e, OnHeap)
     call.r = ropecg(p.module, "#setLengthStr($1, $2)", [
@@ -1701,9 +1701,9 @@ proc genSwap(p: BProc, e: PNode, d: var TLoc) =
   # a = b
   # b = temp
   var a, b, tmp: TLoc
-  getTemp(p, skipTypes(e.sons[1].typ, abstractVar), tmp)
-  initLocExpr(p, e.sons[1], a) # eval a
-  initLocExpr(p, e.sons[2], b) # eval b
+  getTemp(p, skipTypes(e[1].typ, abstractVar), tmp)
+  initLocExpr(p, e[1], a) # eval a
+  initLocExpr(p, e[2], b) # eval b
   genAssignment(p, tmp, a, {})
   genAssignment(p, a, b, {})
   genAssignment(p, b, tmp, {})
@@ -1726,13 +1726,13 @@ proc fewCmps(conf: ConfigRef; s: PNode): bool =
   elif elemType(s.typ).kind in {tyInt, tyInt16..tyInt64}:
     result = true             # better not emit the set if int is basetype!
   else:
-    result = len(s) <= 8  # 8 seems to be a good value
+    result = s.len <= 8  # 8 seems to be a good value
 
 template binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) =
   putIntoDest(p, d, e, frmt % [rdLoc(a), rdSetElemLoc(p.config, b, a.t)])
 
 proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) =
-  case int(getSize(p.config, skipTypes(e.sons[1].typ, abstractVar)))
+  case int(getSize(p.config, skipTypes(e[1].typ, abstractVar)))
   of 1: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&7U)))!=0)")
   of 2: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&15U)))!=0)")
   of 4: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&31U)))!=0)")
@@ -1742,47 +1742,46 @@ proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) =
 template binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: string) =
   var a, b: TLoc
   assert(d.k == locNone)
-  initLocExpr(p, e.sons[1], a)
-  initLocExpr(p, e.sons[2], b)
+  initLocExpr(p, e[1], a)
+  initLocExpr(p, e[2], b)
   lineF(p, cpsStmts, frmt, [rdLoc(a), rdSetElemLoc(p.config, b, a.t)])
 
 proc genInOp(p: BProc, e: PNode, d: var TLoc) =
   var a, b, x, y: TLoc
-  if (e.sons[1].kind == nkCurly) and fewCmps(p.config, e.sons[1]):
+  if (e[1].kind == nkCurly) and fewCmps(p.config, e[1]):
     # a set constructor but not a constant set:
     # do not emit the set, but generate a bunch of comparisons; and if we do
     # so, we skip the unnecessary range check: This is a semantical extension
     # that code now relies on. :-/ XXX
-    let ea = if e.sons[2].kind in {nkChckRange, nkChckRange64}:
-               e.sons[2].sons[0]
+    let ea = if e[2].kind in {nkChckRange, nkChckRange64}:
+               e[2][0]
              else:
-               e.sons[2]
+               e[2]
     initLocExpr(p, ea, a)
     initLoc(b, locExpr, e, OnUnknown)
-    var length = len(e.sons[1])
-    if length > 0:
+    if e[1].len > 0:
       b.r = rope("(")
-      for i in 0 ..< length:
-        let it = e.sons[1].sons[i]
+      for i in 0..<e[1].len:
+        let it = e[1][i]
         if it.kind == nkRange:
-          initLocExpr(p, it.sons[0], x)
-          initLocExpr(p, it.sons[1], y)
-          addf(b.r, "$1 >= $2 && $1 <= $3",
+          initLocExpr(p, it[0], x)
+          initLocExpr(p, it[1], y)
+          b.r.addf("$1 >= $2 && $1 <= $3",
                [rdCharLoc(a), rdCharLoc(x), rdCharLoc(y)])
         else:
           initLocExpr(p, it, x)
-          addf(b.r, "$1 == $2", [rdCharLoc(a), rdCharLoc(x)])
-        if i < length - 1: add(b.r, " || ")
-      add(b.r, ")")
+          b.r.addf("$1 == $2", [rdCharLoc(a), rdCharLoc(x)])
+        if i < e[1].len - 1: b.r.add(" || ")
+      b.r.add(")")
     else:
       # handle the case of an empty set
       b.r = rope("0")
     putIntoDest(p, d, e, b.r)
   else:
-    assert(e.sons[1].typ != nil)
-    assert(e.sons[2].typ != nil)
-    initLocExpr(p, e.sons[1], a)
-    initLocExpr(p, e.sons[2], b)
+    assert(e[1].typ != nil)
+    assert(e[2].typ != nil)
+    initLocExpr(p, e[1], a)
+    initLocExpr(p, e[2], b)
     genInExprAux(p, e, a, b, d)
 
 proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
@@ -1800,7 +1799,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       "& ~",
       "^"]
   var a, b, i: TLoc
-  var setType = skipTypes(e.sons[1].typ, abstractVar)
+  var setType = skipTypes(e[1].typ, abstractVar)
   var size = int(getSize(p.config, setType))
   case size
   of 1, 2, 4, 8:
@@ -1838,12 +1837,12 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     of mExcl: binaryStmtInExcl(p, e, d, "$1[(NU)($2)>>3] &= ~(1U<<($2&7U));$n")
     of mCard:
       var a: TLoc
-      initLocExpr(p, e.sons[1], a)
+      initLocExpr(p, e[1], a)
       putIntoDest(p, d, e, ropecg(p.module, "#cardSet($1, $2)", [rdCharLoc(a), size]))
     of mLtSet, mLeSet:
       getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i) # our counter
-      initLocExpr(p, e.sons[1], a)
-      initLocExpr(p, e.sons[2], b)
+      initLocExpr(p, e[1], a)
+      initLocExpr(p, e[2], b)
       if d.k == locNone: getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyBool), d)
       if op == mLtSet:
         linefmt(p, cpsStmts, lookupOpr[mLtSet],
@@ -1853,16 +1852,16 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
            [rdLoc(i), size, rdLoc(d), rdLoc(a), rdLoc(b)])
     of mEqSet:
       var a, b: TLoc
-      assert(e.sons[1].typ != nil)
-      assert(e.sons[2].typ != nil)
-      initLocExpr(p, e.sons[1], a)
-      initLocExpr(p, e.sons[2], b)
+      assert(e[1].typ != nil)
+      assert(e[2].typ != nil)
+      initLocExpr(p, e[1], a)
+      initLocExpr(p, e[2], b)
       putIntoDest(p, d, e, ropecg(p.module, "(#nimCmpMem($1, $2, $3)==0)", [a.rdCharLoc, b.rdCharLoc, size]))
     of mMulSet, mPlusSet, mMinusSet, mSymDiffSet:
       # we inline the simple for loop for better code generation:
       getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i) # our counter
-      initLocExpr(p, e.sons[1], a)
-      initLocExpr(p, e.sons[2], b)
+      initLocExpr(p, e[1], a)
+      initLocExpr(p, e[2], b)
       if d.k == locNone: getTemp(p, setType, d)
       lineF(p, cpsStmts,
            "for ($1 = 0; $1 < $2; $1++) $n" &
@@ -1881,9 +1880,9 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
   # we use whatever C gives us. Except if we have a value-type, we need to go
   # through its address:
   var a: TLoc
-  initLocExpr(p, e.sons[1], a)
+  initLocExpr(p, e[1], a)
   let etyp = skipTypes(e.typ, abstractRange+{tyOwned})
-  let srcTyp = skipTypes(e.sons[1].typ, abstractRange)
+  let srcTyp = skipTypes(e[1].typ, abstractRange)
   if etyp.kind in ValueTypes and lfIndirect notin a.flags:
     putIntoDest(p, d, e, "(*($1*) ($2))" %
         [getTypeDesc(p.module, e.typ), addrLoc(p.config, a)], a.storage)
@@ -1906,7 +1905,7 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
   const ValueTypes = {tyFloat..tyFloat128, tyTuple, tyObject, tyArray}
   let
     destt = skipTypes(e.typ, abstractRange)
-    srct = skipTypes(e.sons[1].typ, abstractRange)
+    srct = skipTypes(e[1].typ, abstractRange)
   if destt.kind in ValueTypes or srct.kind in ValueTypes:
     # 'cast' and some float type involved? --> use a union.
     inc(p.labels)
@@ -1914,12 +1913,12 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
     var tmp: TLoc
     tmp.r = "LOC$1.source" % [lbl]
     linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n",
-      [getTypeDesc(p.module, e.sons[1].typ), getTypeDesc(p.module, e.typ), lbl])
+      [getTypeDesc(p.module, e[1].typ), getTypeDesc(p.module, e.typ), lbl])
     tmp.k = locExpr
     tmp.lode = lodeTyp srct
     tmp.storage = OnStack
     tmp.flags = {}
-    expr(p, e.sons[1], tmp)
+    expr(p, e[1], tmp)
     putIntoDest(p, d, e, "LOC$#.dest" % [lbl], tmp.storage)
   else:
     # I prefer the shorter cast version for pointer types -> generate less
@@ -1931,27 +1930,27 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc, magic: string) =
   var dest = skipTypes(n.typ, abstractVar)
   if optRangeCheck notin p.options or (dest.kind in {tyUInt..tyUInt64} and
       checkUnsignedConversions notin p.config.legacyFeatures):
-    initLocExpr(p, n.sons[0], a)
+    initLocExpr(p, n[0], a)
     putIntoDest(p, d, n, "(($1) ($2))" %
         [getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage)
   else:
     let mm = if dest.kind in {tyUInt32, tyUInt64, tyUInt}: "chckRangeU" else: magic
-    initLocExpr(p, n.sons[0], a)
+    initLocExpr(p, n[0], a)
     putIntoDest(p, d, lodeTyp dest, ropecg(p.module, "(($1)#$5($2, $3, $4))", [
         getTypeDesc(p.module, dest), rdCharLoc(a),
-        genLiteral(p, n.sons[1], dest), genLiteral(p, n.sons[2], dest),
+        genLiteral(p, n[1], dest), genLiteral(p, n[2], dest),
         mm]), a.storage)
 
 proc genConv(p: BProc, e: PNode, d: var TLoc) =
   let destType = e.typ.skipTypes({tyVar, tyLent, tyGenericInst, tyAlias, tySink})
-  if sameBackendType(destType, e.sons[1].typ):
-    expr(p, e.sons[1], d)
+  if sameBackendType(destType, e[1].typ):
+    expr(p, e[1], d)
   else:
     genSomeCast(p, e, d)
 
 proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) =
   var a: TLoc
-  initLocExpr(p, n.sons[0], a)
+  initLocExpr(p, n[0], a)
   putIntoDest(p, d, n,
               ropecg(p.module, "#nimToCStringConv($1)", [rdLoc(a)]),
 #                "($1 ? $1->data : (NCSTRING)\"\")" % [a.rdLoc],
@@ -1959,7 +1958,7 @@ proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) =
 
 proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) =
   var a: TLoc
-  initLocExpr(p, n.sons[0], a)
+  initLocExpr(p, n[0], a)
   putIntoDest(p, d, n,
               ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]),
               a.storage)
@@ -1967,14 +1966,14 @@ proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) =
 
 proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
   var x: TLoc
-  var a = e.sons[1]
-  var b = e.sons[2]
+  var a = e[1]
+  var b = e[2]
   if a.kind in {nkStrLit..nkTripleStrLit} and a.strVal == "":
-    initLocExpr(p, e.sons[2], x)
+    initLocExpr(p, e[2], x)
     putIntoDest(p, d, e,
       ropecg(p.module, "($1 == 0)", [lenExpr(p, x)]))
   elif b.kind in {nkStrLit..nkTripleStrLit} and b.strVal == "":
-    initLocExpr(p, e.sons[1], x)
+    initLocExpr(p, e[1], x)
     putIntoDest(p, d, e,
       ropecg(p.module, "($1 == 0)", [lenExpr(p, x)]))
   else:
@@ -1984,10 +1983,10 @@ proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
   if {optNaNCheck, optInfCheck} * p.options != {}:
     const opr: array[mAddF64..mDivF64, string] = ["+", "-", "*", "/"]
     var a, b: TLoc
-    assert(e.sons[1].typ != nil)
-    assert(e.sons[2].typ != nil)
-    initLocExpr(p, e.sons[1], a)
-    initLocExpr(p, e.sons[2], b)
+    assert(e[1].typ != nil)
+    assert(e[2].typ != nil)
+    initLocExpr(p, e[1], a)
+    initLocExpr(p, e[2], b)
     putIntoDest(p, d, e, ropecg(p.module, "(($4)($2) $1 ($4)($3))",
                               [opr[m], rdLoc(a), rdLoc(b),
                               getSimpleTypeDesc(p.module, e[1].typ)]))
@@ -2100,21 +2099,21 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
                                                "subInt64"]
     const fun: array[mInc..mDec, string] = ["addInt",
                                              "subInt"]
-    let underlying = skipTypes(e.sons[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent, tyRange})
+    let underlying = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent, tyRange})
     if optOverflowCheck notin p.options or underlying.kind in {tyUInt..tyUInt64}:
       binaryStmt(p, e, d, opr[op])
     else:
       var a, b: TLoc
-      assert(e.sons[1].typ != nil)
-      assert(e.sons[2].typ != nil)
-      initLocExpr(p, e.sons[1], a)
-      initLocExpr(p, e.sons[2], b)
+      assert(e[1].typ != nil)
+      assert(e[2].typ != nil)
+      initLocExpr(p, e[1], a)
+      initLocExpr(p, e[2], b)
 
-      let ranged = skipTypes(e.sons[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent})
+      let ranged = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent})
       let res = binaryArithOverflowRaw(p, ranged, a, b,
         if underlying.kind == tyInt64: fun64[op] else: fun[op])
 
-      putIntoDest(p, a, e.sons[1], "($#)($#)" % [
+      putIntoDest(p, a, e[1], "($#)($#)" % [
         getTypeDesc(p.module, ranged), res])
 
   of mConStrStr: genStrConcat(p, e, d)
@@ -2124,14 +2123,14 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     else:
       var dest, b, call: TLoc
       initLoc(call, locCall, e, OnHeap)
-      initLocExpr(p, e.sons[1], dest)
-      initLocExpr(p, e.sons[2], b)
+      initLocExpr(p, e[1], dest)
+      initLocExpr(p, e[2], b)
       call.r = ropecg(p.module, "#addChar($1, $2)", [rdLoc(dest), rdLoc(b)])
       genAssignment(p, dest, call, {})
   of mAppendStrStr: genStrAppend(p, e, d)
   of mAppendSeqElem:
     if optSeqDestructors in p.config.globalOptions:
-      e.sons[1] = makeAddr(e[1])
+      e[1] = makeAddr(e[1])
       genCall(p, e, d)
     else:
       genSeqElemAppend(p, e, d)
@@ -2145,7 +2144,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   of mCharToStr: genDollar(p, e, d, "#nimCharToStr($1)")
   of mFloatToStr: genDollar(p, e, d, "#nimFloatToStr($1)")
   of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)")
-  of mStrToStr, mUnown: expr(p, e.sons[1], d)
+  of mStrToStr, mUnown: expr(p, e[1], d)
   of mEnumToStr:
     if optTinyRtti in p.config.globalOptions:
       genEnumToStr(p, e, d)
@@ -2157,10 +2156,10 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   of mNewSeq: genNewSeq(p, e)
   of mNewSeqOfCap: genNewSeqOfCap(p, e, d)
   of mSizeOf:
-    let t = e.sons[1].typ.skipTypes({tyTypeDesc})
+    let t = e[1].typ.skipTypes({tyTypeDesc})
     putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t)])
   of mAlignOf:
-    let t = e.sons[1].typ.skipTypes({tyTypeDesc})
+    let t = e[1].typ.skipTypes({tyTypeDesc})
     if not p.module.compileToCpp:
       p.module.includeHeader("<stdalign.h>")
     putIntoDest(p, d, e, "((NI)alignof($1))" % [getTypeDesc(p.module, t)])
@@ -2209,7 +2208,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   of mCopyStr, mCopyStrLast:
     genCall(p, e, d)
   of mNewString, mNewStringOfCap, mExit, mParseBiggestFloat:
-    var opr = e.sons[0].sym
+    var opr = e[0].sym
     # Why would anyone want to set nodecl to one of these hardcoded magics?
     # - not sure, and it wouldn't work if the symbol behind the magic isn't
     #   somehow forward-declared from some other usage, but it is *possible*
@@ -2230,7 +2229,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       discard cgsym(p.module, $opr.loc.r)
       # make sure we have pointer-initialising code for hot code reloading
       if not wasDeclared and p.hcrOn:
-        addf(p.module.s[cfsDynLibInit], "\t$1 = ($2) hcrGetProc($3, \"$1\");$n",
+        p.module.s[cfsDynLibInit].addf("\t$1 = ($2) hcrGetProc($3, \"$1\");$n",
              [mangleDynLibProc(prc), getTypeDesc(p.module, prc.loc.t), getModuleDllPath(p.module, prc)])
     genCall(p, e, d)
   of mDefault: genDefault(p, e, d)
@@ -2238,7 +2237,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   of mEcho: genEcho(p, e[1].skipConv)
   of mArrToSeq: genArrToSeq(p, e, d)
   of mNLen..mNError, mSlurp..mQuoteAst:
-    localError(p.config, e.info, strutils.`%`(errXMustBeCompileTime, e.sons[0].sym.name.s))
+    localError(p.config, e.info, strutils.`%`(errXMustBeCompileTime, e[0].sym.name.s))
   of mSpawn:
     when defined(leanCompiler):
       quit "compiler built without support for the 'spawn' statement"
@@ -2255,7 +2254,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     var a, b: TLoc
     let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1]
     initLocExpr(p, x, a)
-    initLocExpr(p, e.sons[2], b)
+    initLocExpr(p, e[2], b)
     genDeepCopy(p, a, b)
   of mDotDot, mEqCString: genCall(p, e, d)
   of mWasMoved: genWasMoved(p, e)
@@ -2288,8 +2287,8 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
       for it in e.sons:
         if it.kind == nkRange:
           getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), idx) # our counter
-          initLocExpr(p, it.sons[0], a)
-          initLocExpr(p, it.sons[1], b)
+          initLocExpr(p, it[0], a)
+          initLocExpr(p, it[1], b)
           lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" &
               "$2[(NU)($1)>>3] |=(1U<<((NU)($1)&7U));$n", [rdLoc(idx), rdLoc(d),
               rdSetElemLoc(p.config, a, e.typ), rdSetElemLoc(p.config, b, e.typ)])
@@ -2304,8 +2303,8 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
       for it in e.sons:
         if it.kind == nkRange:
           getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), idx) # our counter
-          initLocExpr(p, it.sons[0], a)
-          initLocExpr(p, it.sons[1], b)
+          initLocExpr(p, it[0], a)
+          initLocExpr(p, it[1], b)
           lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" &
               "$2 |=(($5)(1)<<(($1)%(sizeof($5)*8)));$n", [
               rdLoc(idx), rdLoc(d), rdSetElemLoc(p.config, a, e.typ),
@@ -2322,17 +2321,17 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
     let t = n.typ
     discard getTypeDesc(p.module, t) # so that any fields are initialized
     if d.k == locNone: getTemp(p, t, d)
-    for i in 0 ..< len(n):
-      var it = n.sons[i]
-      if it.kind == nkExprColonExpr: it = it.sons[1]
+    for i in 0..<n.len:
+      var it = n[i]
+      if it.kind == nkExprColonExpr: it = it[1]
       initLoc(rec, locExpr, it, d.storage)
       rec.r = "$1.Field$2" % [rdLoc(d), rope(i)]
       rec.flags.incl(lfEnforceDeref)
       expr(p, it, rec)
 
 proc isConstClosure(n: PNode): bool {.inline.} =
-  result = n.sons[0].kind == nkSym and isRoutine(n.sons[0].sym) and
-      n.sons[1].kind == nkNilLit
+  result = n[0].kind == nkSym and isRoutine(n[0].sym) and
+      n[1].kind == nkNilLit
 
 proc genClosure(p: BProc, n: PNode, d: var TLoc) =
   assert n.kind in {nkPar, nkTupleConstr, nkClosure}
@@ -2340,14 +2339,14 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) =
   if isConstClosure(n):
     inc(p.module.labels)
     var tmp = "CNSTCLOSURE" & rope(p.module.labels)
-    addf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n",
+    p.module.s[cfsData].addf("static NIM_CONST $1 $2 = $3;$n",
         [getTypeDesc(p.module, n.typ), tmp, genConstExpr(p, n)])
     putIntoDest(p, d, n, tmp, OnStatic)
   else:
     var tmp, a, b: TLoc
-    initLocExpr(p, n.sons[0], a)
-    initLocExpr(p, n.sons[1], b)
-    if n.sons[0].skipConv.kind == nkClosure:
+    initLocExpr(p, n[0], a)
+    initLocExpr(p, n[1], b)
+    if n[0].skipConv.kind == nkClosure:
       internalError(p.config, n.info, "closure to closure created")
     # tasyncawait.nim breaks with this optimization:
     when false:
@@ -2364,10 +2363,10 @@ proc genArrayConstr(p: BProc, n: PNode, d: var TLoc) =
   var arr: TLoc
   if not handleConstExpr(p, n, d):
     if d.k == locNone: getTemp(p, n.typ, d)
-    for i in 0 ..< len(n):
+    for i in 0..<n.len:
       initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), d.storage)
       arr.r = "$1[$2]" % [rdLoc(d), intLiteral(i)]
-      expr(p, n.sons[i], arr)
+      expr(p, n[i], arr)
 
 proc genComplexConst(p: BProc, sym: PSym, d: var TLoc) =
   requestConstImpl(p, sym)
@@ -2380,7 +2379,7 @@ template genStmtListExprImpl(exprOrStmt) {.dirty.} =
       sfSystemModule notin p.module.module.flags and
       optStackTrace in p.prc.options
   var frameName: Rope = nil
-  for i in 0 .. n.len - 2:
+  for i in 0..<n.len - 1:
     let it = n[i]
     if it.kind == nkComesFrom:
       if hasNimFrame and frameName == nil:
@@ -2394,19 +2393,19 @@ template genStmtListExprImpl(exprOrStmt) {.dirty.} =
       genStmts(p, it)
   if n.len > 0: exprOrStmt
   if frameName != nil:
-    add p.s(cpsStmts), deinitFrameNoDebug(p, frameName)
+    p.s(cpsStmts).add deinitFrameNoDebug(p, frameName)
 
 proc genStmtListExpr(p: BProc, n: PNode, d: var TLoc) =
   genStmtListExprImpl:
-    expr(p, n[n.len - 1], d)
+    expr(p, n[^1], d)
 
 proc genStmtList(p: BProc, n: PNode) =
   genStmtListExprImpl:
-    genStmts(p, n[n.len - 1])
+    genStmts(p, n[^1])
 
 proc upConv(p: BProc, n: PNode, d: var TLoc) =
   var a: TLoc
-  initLocExpr(p, n.sons[0], a)
+  initLocExpr(p, n[0], a)
   let dest = skipTypes(n.typ, abstractPtrs)
   if optObjCheck in p.options and not isObjLackingTypeField(dest):
     var r = rdLoc(a)
@@ -2419,9 +2418,9 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
       t = skipTypes(t.lastSon, abstractInst)
     discard getTypeDesc(p.module, t)
     if not p.module.compileToCpp:
-      while t.kind == tyObject and t.sons[0] != nil:
-        add(r, ".Sup")
-        t = skipTypes(t.sons[0], skipPtrs)
+      while t.kind == tyObject and t[0] != nil:
+        r.add(".Sup")
+        t = skipTypes(t[0], skipPtrs)
     let checkFor = if optTinyRtti in p.config.globalOptions:
                      genTypeInfo2Name(p.module, dest)
                    else:
@@ -2432,7 +2431,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
     else:
       linefmt(p, cpsStmts, "#chckObj($1.m_type, $2);$n",
               [r, checkFor])
-  if n.sons[0].typ.kind != tyObject:
+  if n[0].typ.kind != tyObject:
     putIntoDest(p, d, n,
                 "(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage)
   else:
@@ -2442,12 +2441,12 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
 proc downConv(p: BProc, n: PNode, d: var TLoc) =
   if p.module.compileToCpp:
     discard getTypeDesc(p.module, skipTypes(n[0].typ, abstractPtrs))
-    expr(p, n.sons[0], d)     # downcast does C++ for us
+    expr(p, n[0], d)     # downcast does C++ for us
   else:
     var dest = skipTypes(n.typ, abstractPtrs)
 
-    var arg = n.sons[0]
-    while arg.kind == nkObjDownConv: arg = arg.sons[0]
+    var arg = n[0]
+    while arg.kind == nkObjDownConv: arg = arg[0]
 
     var src = skipTypes(arg.typ, abstractPtrs)
     discard getTypeDesc(p.module, src)
@@ -2456,10 +2455,10 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
     var r = rdLoc(a)
     let isRef = skipTypes(arg.typ, abstractInstOwned).kind in {tyRef, tyPtr, tyVar, tyLent}
     if isRef:
-      add(r, "->Sup")
+      r.add("->Sup")
     else:
-      add(r, ".Sup")
-    for i in 2 .. abs(inheritanceDiff(dest, src)): add(r, ".Sup")
+      r.add(".Sup")
+    for i in 2..abs(inheritanceDiff(dest, src)): r.add(".Sup")
     if isRef:
       # it can happen that we end up generating '&&x->Sup' here, so we pack
       # the '&x->Sup' into a temporary and then those address is taken
@@ -2484,7 +2483,7 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
   if id == p.module.labels:
     # expression not found in the cache:
     inc(p.module.labels)
-    addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
+    p.module.s[cfsData].addf("NIM_CONST $1 $2 = $3;$n",
          [getTypeDesc(p.module, t), tmp, genConstExpr(p, n)])
 
   if d.k == locNone:
@@ -2574,7 +2573,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
   of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand,
      nkCallStrLit:
     genLineDir(p, n) # may be redundant, it is generated in fixupCall as well
-    let op = n.sons[0]
+    let op = n[0]
     if n.typ.isNil:
       # discard the value:
       var a: TLoc
@@ -2621,7 +2620,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
   of nkIfExpr, nkIfStmt: genIf(p, n, d)
   of nkWhen:
     # This should be a "when nimvm" node.
-    expr(p, n.sons[1].sons[0], d)
+    expr(p, n[1][0], d)
   of nkObjDownConv: downConv(p, n, d)
   of nkObjUpConv: upConv(p, n, d)
   of nkChckRangeF: genRangeChck(p, n, d, "chckRangeF")
@@ -2630,7 +2629,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
   of nkStringToCString: convStrToCStr(p, n, d)
   of nkCStringToString: convCStrToStr(p, n, d)
   of nkLambdaKinds:
-    var sym = n.sons[namePos].sym
+    var sym = n[namePos].sym
     genProc(p.module, sym)
     if sym.loc.r == nil or sym.loc.lode == nil:
       internalError(p.config, n.info, "expr: proc not init " & sym.name.s)
@@ -2678,8 +2677,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
   of nkPragma: genPragma(p, n)
   of nkPragmaBlock: expr(p, n.lastSon, d)
   of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef:
-    if n.sons[genericParamsPos].kind == nkEmpty:
-      var prc = n.sons[namePos].sym
+    if n[genericParamsPos].kind == nkEmpty:
+      var prc = n[namePos].sym
       # due to a bug/limitation in the lambda lifting, unused inner procs
       # are not transformed correctly. We work around this issue (#411) here
       # by ensuring it's no inner proc (owner is a module):
@@ -2699,7 +2698,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
   else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind")
 
 proc genNamedConstExpr(p: BProc, n: PNode): Rope =
-  if n.kind == nkExprColonExpr: result = genConstExpr(p, n.sons[1])
+  if n.kind == nkExprColonExpr: result = genConstExpr(p, n[1])
   else: result = genConstExpr(p, n)
 
 proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
@@ -2728,9 +2727,9 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
       result = rope"{}"
   of tyTuple:
     result = rope"{"
-    for i in 0 ..< typ.len:
+    for i in 0..<typ.len:
       if i > 0: result.add ", "
-      result.add getDefaultValue(p, typ.sons[i], info)
+      result.add getDefaultValue(p, typ[i], info)
     result.add "}"
   of tyArray: result = rope"{}"
   of tySet:
@@ -2746,9 +2745,9 @@ proc getNullValueAux(p: BProc; t: PType; obj, cons: PNode,
     for it in obj.sons:
       getNullValueAux(p, t, it, cons, result, count)
   of nkRecCase:
-    getNullValueAux(p, t, obj.sons[0], cons, result, count)
-    for i in 1 ..< len(obj):
-      getNullValueAux(p, t, lastSon(obj.sons[i]), cons, result, count)
+    getNullValueAux(p, t, obj[0], cons, result, count)
+    for i in 1..<obj.len:
+      getNullValueAux(p, t, lastSon(obj[i]), cons, result, count)
   of nkSym:
     if count > 0: result.add ", "
     inc count
@@ -2768,7 +2767,7 @@ proc getNullValueAux(p: BProc; t: PType; obj, cons: PNode,
 
 proc getNullValueAuxT(p: BProc; orig, t: PType; obj, cons: PNode,
                       result: var Rope; count: var int) =
-  var base = t.sons[0]
+  var base = t[0]
   let oldRes = result
   if not p.module.compileToCpp: result.add "{"
   let oldcount = count
@@ -2776,7 +2775,7 @@ proc getNullValueAuxT(p: BProc; orig, t: PType; obj, cons: PNode,
     base = skipTypes(base, skipPtrs)
     getNullValueAuxT(p, orig, base, base.n, cons, result, count)
   elif not isObjLackingTypeField(t) and not p.module.compileToCpp:
-    addf(result, "$1", [genTypeInfo(p.module, orig, obj.info)])
+    result.addf("$1", [genTypeInfo(p.module, orig, obj.info)])
     inc count
   getNullValueAux(p, t, obj, cons, result, count)
   # do not emit '{}' as that is not valid C:
@@ -2788,34 +2787,33 @@ proc genConstObjConstr(p: BProc; n: PNode): Rope =
   let t = n.typ.skipTypes(abstractInstOwned)
   var count = 0
   #if not isObjLackingTypeField(t) and not p.module.compileToCpp:
-  #  addf(result, "{$1}", [genTypeInfo(p.module, t)])
+  #  result.addf("{$1}", [genTypeInfo(p.module, t)])
   #  inc count
   getNullValueAuxT(p, t, t, t.n, n, result, count)
   if p.module.compileToCpp:
     result = "{$1}$n" % [result]
 
 proc genConstSimpleList(p: BProc, n: PNode): Rope =
-  var length = len(n)
   result = rope("{")
-  for i in 0 .. length - 2:
-    addf(result, "$1,$n", [genNamedConstExpr(p, n.sons[i])])
-  if length > 0:
-    add(result, genNamedConstExpr(p, n.sons[length - 1]))
-  addf(result, "}$n", [])
+  for i in 0..<n.len - 1:
+    result.addf("$1,$n", [genNamedConstExpr(p, n[i])])
+  if n.len > 0:
+    result.add(genNamedConstExpr(p, n[^1]))
+  result.addf("}$n", [])
 
 proc genConstSeq(p: BProc, n: PNode, t: PType): Rope =
   var data = "{{$1, $1 | NIM_STRLIT_FLAG}" % [n.len.rope]
   if n.len > 0:
     # array part needs extra curlies:
     data.add(", {")
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       if i > 0: data.addf(",$n", [])
-      data.add genConstExpr(p, n.sons[i])
+      data.add genConstExpr(p, n[i])
     data.add("}")
   data.add("}")
 
   result = getTempName(p.module)
-  let base = t.skipTypes(abstractInst).sons[0]
+  let base = t.skipTypes(abstractInst)[0]
 
   appcg(p.module, cfsData,
         "NIM_CONST struct {$n" &
@@ -2828,25 +2826,25 @@ proc genConstSeq(p: BProc, n: PNode, t: PType): Rope =
 
 proc genConstSeqV2(p: BProc, n: PNode, t: PType): Rope =
   var data = rope"{"
-  for i in 0 ..< n.len:
+  for i in 0..<n.len:
     if i > 0: data.addf(",$n", [])
-    data.add genConstExpr(p, n.sons[i])
+    data.add genConstExpr(p, n[i])
   data.add("}")
 
   let payload = getTempName(p.module)
-  let base = t.skipTypes(abstractInst).sons[0]
+  let base = t.skipTypes(abstractInst)[0]
 
   appcg(p.module, cfsData,
     "static const struct {$n" &
     "  NI cap; void* allocator; $1 data[$2];$n" &
     "} $3 = {$2, NIM_NIL, $4};$n", [
-    getTypeDesc(p.module, base), len(n), payload, data])
-  result = "{$1, ($2*)&$3}" % [rope(len(n)), getSeqPayloadType(p.module, t), payload]
+    getTypeDesc(p.module, base), n.len, payload, data])
+  result = "{$1, ($2*)&$3}" % [rope(n.len), getSeqPayloadType(p.module, t), payload]
 
 proc genConstExpr(p: BProc, n: PNode): Rope =
   case n.kind
   of nkHiddenStdConv, nkHiddenSubConv:
-    result = genConstExpr(p, n.sons[1])
+    result = genConstExpr(p, n[1])
   of nkCurly:
     var cs: TBitSet
     toBitSet(p.config, n, cs)
@@ -2859,7 +2857,7 @@ proc genConstExpr(p: BProc, n: PNode): Rope =
       else:
         result = genConstSeq(p, n, n.typ)
     elif t.kind == tyProc and t.callConv == ccClosure and n.len > 1 and
-         n.sons[1].kind == nkNilLit:
+         n[1].kind == nkNilLit:
       # Conversion: nimcall -> closure.
       # this hack fixes issue that nkNilLit is expanded to {NIM_NIL,NIM_NIL}
       # this behaviour is needed since closure_var = nil must be
diff --git a/compiler/ccgliterals.nim b/compiler/ccgliterals.nim
index 0dd12452c..a016bdcaa 100644
--- a/compiler/ccgliterals.nim
+++ b/compiler/ccgliterals.nim
@@ -35,8 +35,8 @@ proc detectSeqVersion(m: BModule): int =
 proc genStringLiteralDataOnlyV1(m: BModule, s: string): Rope =
   discard cgsym(m, "TGenericSeq")
   result = getTempName(m)
-  addf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n",
-       [result, makeCString(s), rope(len(s))])
+  m.s[cfsData].addf("STRING_LITERAL($1, $2, $3);$n",
+       [result, makeCString(s), rope(s.len)])
 
 proc genStringLiteralV1(m: BModule; n: PNode): Rope =
   if s.isNil:
@@ -54,10 +54,10 @@ proc genStringLiteralV1(m: BModule; n: PNode): Rope =
 # ------ Version 2: destructor based strings and seqs -----------------------
 
 proc genStringLiteralDataOnlyV2(m: BModule, s: string; result: Rope) =
-  addf(m.s[cfsData], "static const struct {$n" &
+  m.s[cfsData].addf("static const struct {$n" &
        "  NI cap; void* allocator; NIM_CHAR data[$2+1];$n" &
        "} $1 = { $2, NIM_NIL, $3 };$n",
-       [result, rope(len(s)), makeCString(s)])
+       [result, rope(s.len), makeCString(s)])
 
 proc genStringLiteralV2(m: BModule; n: PNode): Rope =
   let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
@@ -68,12 +68,12 @@ proc genStringLiteralV2(m: BModule; n: PNode): Rope =
     discard cgsym(m, "NimStrPayload")
     discard cgsym(m, "NimStringV2")
     # string literal not found in the cache:
-    addf(m.s[cfsData], "static const NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
-          [result, rope(len(n.strVal)), pureLit])
+    m.s[cfsData].addf("static const NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
+          [result, rope(n.strVal.len), pureLit])
   else:
     result = getTempName(m)
-    addf(m.s[cfsData], "static const NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
-          [result, rope(len(n.strVal)), m.tmpBase & rope(id)])
+    m.s[cfsData].addf("static const NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
+          [result, rope(n.strVal.len), m.tmpBase & rope(id)])
 
 proc genStringLiteralV2Const(m: BModule; n: PNode): Rope =
   let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
@@ -86,7 +86,7 @@ proc genStringLiteralV2Const(m: BModule; n: PNode): Rope =
     genStringLiteralDataOnlyV2(m, n.strVal, pureLit)
   else:
     pureLit = m.tmpBase & rope(id)
-  result = "{$1, (NimStrPayload*)&$2}" % [rope(len(n.strVal)), pureLit]
+  result = "{$1, (NimStrPayload*)&$2}" % [rope(n.strVal.len), pureLit]
 
 # ------ Version selector ---------------------------------------------------
 
diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim
index cdb43f20f..2d7e0bda7 100644
--- a/compiler/ccgmerge.nim
+++ b/compiler/ccgmerge.nim
@@ -50,9 +50,9 @@ const
 proc genSectionStart*(fs: TCFileSection; conf: ConfigRef): Rope =
   if compilationCachePresent(conf):
     result = nil
-    add(result, "\n/*\t")
-    add(result, CFileSectionNames[fs])
-    add(result, ":*/\n")
+    result.add("\n/*\t")
+    result.add(CFileSectionNames[fs])
+    result.add(":*/\n")
 
 proc genSectionEnd*(fs: TCFileSection; conf: ConfigRef): Rope =
   if compilationCachePresent(conf):
@@ -61,9 +61,9 @@ proc genSectionEnd*(fs: TCFileSection; conf: ConfigRef): Rope =
 proc genSectionStart*(ps: TCProcSection; conf: ConfigRef): Rope =
   if compilationCachePresent(conf):
     result = rope("")
-    add(result, "\n/*\t")
-    add(result, CProcSectionNames[ps])
-    add(result, ":*/\n")
+    result.add("\n/*\t")
+    result.add(CProcSectionNames[ps])
+    result.add(":*/\n")
 
 proc genSectionEnd*(ps: TCProcSection; conf: ConfigRef): Rope =
   if compilationCachePresent(conf):
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index a3d807e26..130c41011 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -46,7 +46,7 @@ proc inExceptBlockLen(p: BProc): int =
 
 proc startBlockInternal(p: BProc): int {.discardable.} =
   inc(p.labels)
-  result = len(p.blocks)
+  result = p.blocks.len
   setLen(p.blocks, result + 1)
   p.blocks[result].id = p.labels
   p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16
@@ -62,16 +62,15 @@ proc endBlock(p: BProc)
 proc genVarTuple(p: BProc, n: PNode) =
   var tup, field: TLoc
   if n.kind != nkVarTuple: internalError(p.config, n.info, "genVarTuple")
-  var L = len(n)
 
   # if we have a something that's been captured, use the lowering instead:
-  for i in 0 .. L-3:
+  for i in 0..<n.len-2:
     if n[i].kind != nkSym:
       genStmts(p, lowerTupleUnpacking(p.module.g.graph, n, p.prc))
       return
 
   # check only the first son
-  var forHcr = treatGlobalDifferentlyForHCR(p.module, n.sons[0].sym)
+  var forHcr = treatGlobalDifferentlyForHCR(p.module, n[0].sym)
   let hcrCond = if forHcr: getTempName(p.module) else: nil
   var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]]
   # determine if the tuple is constructed at top-level scope or inside of a block (if/while/block)
@@ -85,10 +84,10 @@ proc genVarTuple(p: BProc, n: PNode) =
     startBlock(p)
 
   genLineDir(p, n)
-  initLocExpr(p, n.sons[L-1], tup)
+  initLocExpr(p, n[^1], tup)
   var t = tup.t.skipTypes(abstractInst)
-  for i in 0 .. L-3:
-    let vn = n.sons[i]
+  for i in 0..<n.len-2:
+    let vn = n[i]
     let v = vn.sym
     if sfCompileTime in v.flags: continue
     var traverseProc: Rope
@@ -100,13 +99,13 @@ proc genVarTuple(p: BProc, n: PNode) =
         registerTraverseProc(p, v, traverseProc)
     else:
       assignLocalVar(p, vn)
-      initLocalVar(p, v, immediateAsgn=isAssignedImmediately(p.config, n[L-1]))
+      initLocalVar(p, v, immediateAsgn=isAssignedImmediately(p.config, n[^1]))
     initLoc(field, locExpr, vn, tup.storage)
     if t.kind == tyTuple:
       field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
     else:
-      if t.n.sons[i].kind != nkSym: internalError(p.config, n.info, "genVarTuple")
-      field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n.sons[i].sym)]
+      if t.n[i].kind != nkSym: internalError(p.config, n.info, "genVarTuple")
+      field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n[i].sym)]
     putLocIntoDest(p, v.loc, field)
     if forHcr or isGlobalInBlock:
       hcrGlobals.add((loc: v.loc, tp: if traverseProc == nil: ~"NULL" else: traverseProc))
@@ -121,12 +120,12 @@ proc genVarTuple(p: BProc, n: PNode) =
     lineCg(p, cpsLocals, "NIM_BOOL $1 = NIM_FALSE;$n", [hcrCond])
     for curr in hcrGlobals:
       lineCg(p, cpsLocals, "$1 |= hcrRegisterGlobal($4, \"$2\", sizeof($3), $5, (void**)&$2);$N",
-              [hcrCond, curr.loc.r, rdLoc(curr.loc), getModuleDllPath(p.module, n.sons[0].sym), curr.tp])
+              [hcrCond, curr.loc.r, rdLoc(curr.loc), getModuleDllPath(p.module, n[0].sym), curr.tp])
 
 
 proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
-  if ri.kind in nkCallKinds and (ri.sons[0].kind != nkSym or
-                                 ri.sons[0].sym.magic == mNone):
+  if ri.kind in nkCallKinds and (ri[0].kind != nkSym or
+                                 ri[0].sym.magic == mNone):
     genAsgnCall(p, le, ri, a)
   else:
     # this is a hacky way to fix #1181 (tmissingderef)::
@@ -153,7 +152,7 @@ proc blockBody(b: var TBlock): Rope =
 proc endBlock(p: BProc, blockEnd: Rope) =
   let topBlock = p.blocks.len-1
   # the block is merged into the parent block
-  add(p.blocks[topBlock-1].sections[cpsStmts], p.blocks[topBlock].blockBody)
+  p.blocks[topBlock-1].sections[cpsStmts].add(p.blocks[topBlock].blockBody)
   setLen(p.blocks, topBlock)
   # this is done after the block is popped so $n is
   # properly indented when pretty printing is enabled
@@ -190,7 +189,7 @@ proc genState(p: BProc, n: PNode) =
   internalAssert p.config, n.len == 1
   let n0 = n[0]
   if n0.kind == nkIntLit:
-    let idx = n.sons[0].intVal
+    let idx = n[0].intVal
     linefmt(p, cpsStmts, "STATE$1: ;$n", [idx])
   elif n0.kind == nkStrLit:
     linefmt(p, cpsStmts, "$1: ;$n", [n0.strVal])
@@ -201,7 +200,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
 
   var stack = newSeq[tuple[fin: PNode, inExcept: bool]](0)
 
-  for i in 1 .. howManyTrys:
+  for i in 1..howManyTrys:
     let tryStmt = p.nestedTryStmts.pop
     if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions:
       # Pop safe points generated by try
@@ -236,7 +235,7 @@ proc genGotoState(p: BProc, n: PNode) =
   #   case 0: goto STATE0;
   # ...
   var a: TLoc
-  initLocExpr(p, n.sons[0], a)
+  initLocExpr(p, n[0], a)
   lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)])
   p.beforeRetNeeded = true
   lineF(p, cpsStmts, "case -1:$n", [])
@@ -244,12 +243,12 @@ proc genGotoState(p: BProc, n: PNode) =
     howManyTrys    = p.nestedTryStmts.len,
     howManyExcepts = p.inExceptBlockLen)
   lineF(p, cpsStmts, " goto BeforeRet_;$n", [])
-  var statesCounter = lastOrd(p.config, n.sons[0].typ)
+  var statesCounter = lastOrd(p.config, n[0].typ)
   if n.len >= 2 and n[1].kind == nkIntLit:
     statesCounter = getInt(n[1])
   let prefix = if n.len == 3 and n[2].kind == nkStrLit: n[2].strVal.rope
                else: rope"STATE"
-  for i in 0i64 .. toInt64(statesCounter):
+  for i in 0i64..toInt64(statesCounter):
     lineF(p, cpsStmts, "case $2: goto $1$2;$n", [prefix, rope(i)])
   lineF(p, cpsStmts, "}$n", [])
 
@@ -257,11 +256,11 @@ proc genBreakState(p: BProc, n: PNode, d: var TLoc) =
   var a: TLoc
   initLoc(d, locExpr, n, OnUnknown)
 
-  if n.sons[0].kind == nkClosure:
-    initLocExpr(p, n.sons[0].sons[1], a)
+  if n[0].kind == nkClosure:
+    initLocExpr(p, n[0][1], a)
     d.r = "(((NI*) $1)[1] < 0)" % [rdLoc(a)]
   else:
-    initLocExpr(p, n.sons[0], a)
+    initLocExpr(p, n[0], a)
     # the environment is guaranteed to contain the 'state' field at offset 1:
     d.r = "((((NI*) $1.ClE_0)[1]) < 0)" % [rdLoc(a)]
 
@@ -322,12 +321,12 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
       if value.kind in nkCallKinds and value[0].kind == nkSym and
            sfConstructor in value[0].sym.flags:
         var params: Rope
-        let typ = skipTypes(value.sons[0].typ, abstractInst)
+        let typ = skipTypes(value[0].typ, abstractInst)
         assert(typ.kind == tyProc)
         for i in 1..<value.len:
           if params != nil: params.add(~", ")
-          assert(len(typ) == len(typ.n))
-          add(params, genOtherArg(p, value, i, typ))
+          assert(typ.len == typ.n.len)
+          params.add(genOtherArg(p, value, i, typ))
         if params == nil:
           lineF(p, cpsStmts, "$#;$n", [decl])
         else:
@@ -368,15 +367,15 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
 proc genSingleVar(p: BProc, a: PNode) =
   let v = a[0].sym
   if sfCompileTime in v.flags: return
-  genSingleVar(p, v, a[0], a.sons[2])
+  genSingleVar(p, v, a[0], a[2])
 
 proc genClosureVar(p: BProc, a: PNode) =
-  var immediateAsgn = a.sons[2].kind != nkEmpty
+  var immediateAsgn = a[2].kind != nkEmpty
   var v: TLoc
-  initLocExpr(p, a.sons[0], v)
+  initLocExpr(p, a[0], v)
   genLineDir(p, a)
   if immediateAsgn:
-    loadInto(p, a.sons[0], a.sons[2], v)
+    loadInto(p, a[0], a[2], v)
   else:
     constructLoc(p, v)
 
@@ -385,7 +384,7 @@ proc genVarStmt(p: BProc, n: PNode) =
     if it.kind == nkCommentStmt: continue
     if it.kind == nkIdentDefs:
       # can be a lifted var nowadays ...
-      if it.sons[0].kind == nkSym:
+      if it[0].kind == nkSym:
         genSingleVar(p, it)
       else:
         genClosureVar(p, it)
@@ -416,53 +415,53 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
     if d.k == locTemp and isEmptyType(n.typ): d.k = locNone
     if it.len == 2:
       startBlock(p)
-      initLocExprSingleUse(p, it.sons[0], a)
+      initLocExprSingleUse(p, it[0], a)
       lelse = getLabel(p)
       inc(p.labels)
       lineF(p, cpsStmts, "if (!$1) goto $2;$n",
             [rdLoc(a), lelse])
       if p.module.compileToCpp:
         # avoid "jump to label crosses initialization" error:
-        add(p.s(cpsStmts), "{")
-        expr(p, it.sons[1], d)
-        add(p.s(cpsStmts), "}")
+        p.s(cpsStmts).add "{"
+        expr(p, it[1], d)
+        p.s(cpsStmts).add "}"
       else:
-        expr(p, it.sons[1], d)
+        expr(p, it[1], d)
       endBlock(p)
-      if len(n) > 1:
+      if n.len > 1:
         lineF(p, cpsStmts, "goto $1;$n", [lend])
       fixLabel(p, lelse)
     elif it.len == 1:
       startBlock(p)
-      expr(p, it.sons[0], d)
+      expr(p, it[0], d)
       endBlock(p)
     else: internalError(p.config, n.info, "genIf()")
-  if len(n) > 1: fixLabel(p, lend)
+  if n.len > 1: fixLabel(p, lend)
 
 proc genReturnStmt(p: BProc, t: PNode) =
   if nfPreventCg in t.flags: return
   p.beforeRetNeeded = true
   genLineDir(p, t)
-  if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0])
+  if (t[0].kind != nkEmpty): genStmts(p, t[0])
   blockLeaveActions(p,
     howManyTrys    = p.nestedTryStmts.len,
     howManyExcepts = p.inExceptBlockLen)
   if (p.finallySafePoints.len > 0) and not p.noSafePoints:
     # If we're in a finally block, and we came here by exception
     # consume it before we return.
-    var safePoint = p.finallySafePoints[p.finallySafePoints.len-1]
+    var safePoint = p.finallySafePoints[^1]
     linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", [safePoint])
   lineF(p, cpsStmts, "goto BeforeRet_;$n", [])
 
 proc genGotoForCase(p: BProc; caseStmt: PNode) =
-  for i in 1 ..< caseStmt.len:
+  for i in 1..<caseStmt.len:
     startBlock(p)
-    let it = caseStmt.sons[i]
-    for j in 0 .. it.len-2:
-      if it.sons[j].kind == nkRange:
+    let it = caseStmt[i]
+    for j in 0..<it.len-1:
+      if it[j].kind == nkRange:
         localError(p.config, it.info, "range notation not available for computed goto")
         return
-      let val = getOrdValue(it.sons[j])
+      let val = getOrdValue(it[j])
       lineF(p, cpsStmts, "NIMSTATE_$#:$n", [val.rope])
     genStmts(p, it.lastSon)
     endBlock(p)
@@ -473,7 +472,7 @@ iterator fieldValuePairs(n: PNode): tuple[memberSym, valueSym: PNode] =
   for identDefs in n:
     if identDefs.kind == nkIdentDefs:
       let valueSym = identDefs[^1]
-      for i in 0 ..< identDefs.len-2:
+      for i in 0..<identDefs.len-2:
         let memberSym = identDefs[i]
         yield((memberSym: memberSym, valueSym: valueSym))
 
@@ -481,22 +480,22 @@ proc genComputedGoto(p: BProc; n: PNode) =
   # first pass: Generate array of computed labels:
   var casePos = -1
   var arraySize: int
-  for i in 0 ..< n.len:
-    let it = n.sons[i]
+  for i in 0..<n.len:
+    let it = n[i]
     if it.kind == nkCaseStmt:
       if lastSon(it).kind != nkOfBranch:
         localError(p.config, it.info,
             "case statement must be exhaustive for computed goto"); return
       casePos = i
-      if enumHasHoles(it.sons[0].typ):
+      if enumHasHoles(it[0].typ):
         localError(p.config, it.info,
             "case statement cannot work on enums with holes for computed goto"); return
-      let aSize = lengthOrd(p.config, it.sons[0].typ)
+      let aSize = lengthOrd(p.config, it[0].typ)
       if aSize > 10_000:
         localError(p.config, it.info,
             "case statement has too many cases for computed goto"); return
       arraySize = toInt(aSize)
-      if firstOrd(p.config, it.sons[0].typ) != 0:
+      if firstOrd(p.config, it[0].typ) != 0:
         localError(p.config, it.info,
             "case statement has to start at 0 for computed goto"); return
   if casePos < 0:
@@ -510,54 +509,54 @@ proc genComputedGoto(p: BProc; n: PNode) =
   gotoArray.addf("&&TMP$#_};$n", [rope(id+arraySize)])
   line(p, cpsLocals, gotoArray)
 
-  for j in 0 ..< casePos:
-    genStmts(p, n.sons[j])
+  for j in 0..<casePos:
+    genStmts(p, n[j])
 
-  let caseStmt = n.sons[casePos]
+  let caseStmt = n[casePos]
   var a: TLoc
-  initLocExpr(p, caseStmt.sons[0], a)
+  initLocExpr(p, caseStmt[0], a)
   # first goto:
   lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
 
-  for i in 1 ..< caseStmt.len:
+  for i in 1..<caseStmt.len:
     startBlock(p)
-    let it = caseStmt.sons[i]
-    for j in 0 .. it.len-2:
-      if it.sons[j].kind == nkRange:
+    let it = caseStmt[i]
+    for j in 0..<it.len-1:
+      if it[j].kind == nkRange:
         localError(p.config, it.info, "range notation not available for computed goto")
         return
 
-      let val = getOrdValue(it.sons[j])
+      let val = getOrdValue(it[j])
       lineF(p, cpsStmts, "TMP$#_:$n", [intLiteral(toInt64(val)+id+1)])
 
     genStmts(p, it.lastSon)
 
-    for j in casePos+1 ..< n.sons.len:
-      genStmts(p, n.sons[j])
+    for j in casePos+1..<n.len:
+      genStmts(p, n[j])
 
-    for j in 0 ..< casePos:
+    for j in 0..<casePos:
       # prevent new local declarations
       # compile declarations as assignments
-      let it = n.sons[j]
+      let it = n[j]
       if it.kind in {nkLetSection, nkVarSection}:
         let asgn = copyNode(it)
         asgn.kind = nkAsgn
         asgn.sons.setLen 2
         for sym, value in it.fieldValuePairs:
           if value.kind != nkEmpty:
-            asgn.sons[0] = sym
-            asgn.sons[1] = value
+            asgn[0] = sym
+            asgn[1] = value
             genStmts(p, asgn)
       else:
         genStmts(p, it)
 
     var a: TLoc
-    initLocExpr(p, caseStmt.sons[0], a)
+    initLocExpr(p, caseStmt[0], a)
     lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
     endBlock(p)
 
-  for j in casePos+1 ..< n.sons.len:
-    genStmts(p, n.sons[j])
+  for j in casePos+1..<n.len:
+    genStmts(p, n[j])
 
 
 proc genWhileStmt(p: BProc, t: PNode) =
@@ -565,23 +564,23 @@ proc genWhileStmt(p: BProc, t: PNode) =
   # significantly worse code
   var
     a: TLoc
-  assert(len(t) == 2)
+  assert(t.len == 2)
   inc(p.withinLoop)
   genLineDir(p, t)
 
   preserveBreakIdx:
-    var loopBody = t.sons[1]
+    var loopBody = t[1]
     if loopBody.stmtsContainPragma(wComputedGoto) and
        hasComputedGoto in CC[p.config.cCompiler].props:
          # for closure support weird loop bodies are generated:
-      if loopBody.len == 2 and loopBody.sons[0].kind == nkEmpty:
-        loopBody = loopBody.sons[1]
+      if loopBody.len == 2 and loopBody[0].kind == nkEmpty:
+        loopBody = loopBody[1]
       genComputedGoto(p, loopBody)
     else:
       p.breakIdx = startBlock(p, "while (1) {$n")
       p.blocks[p.breakIdx].isLoop = true
-      initLocExpr(p, t.sons[0], a)
-      if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
+      initLocExpr(p, t[0], a)
+      if (t[0].kind != nkIntLit) or (t[0].intVal == 0):
         let label = assignLabel(p.blocks[p.breakIdx])
         lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), label])
       genStmts(p, loopBody)
@@ -602,30 +601,30 @@ proc genBlock(p: BProc, n: PNode, d: var TLoc) =
     d.flags.incl(lfEnforceDeref)
   preserveBreakIdx:
     p.breakIdx = startBlock(p)
-    if n.sons[0].kind != nkEmpty:
+    if n[0].kind != nkEmpty:
       # named block?
-      assert(n.sons[0].kind == nkSym)
-      var sym = n.sons[0].sym
+      assert(n[0].kind == nkSym)
+      var sym = n[0].sym
       sym.loc.k = locOther
       sym.position = p.breakIdx+1
-    expr(p, n.sons[1], d)
+    expr(p, n[1], d)
     endBlock(p)
 
 proc genParForStmt(p: BProc, t: PNode) =
-  assert(len(t) == 3)
+  assert(t.len == 3)
   inc(p.withinLoop)
   genLineDir(p, t)
 
   preserveBreakIdx:
-    let forLoopVar = t.sons[0].sym
+    let forLoopVar = t[0].sym
     var rangeA, rangeB: TLoc
-    assignLocalVar(p, t.sons[0])
+    assignLocalVar(p, t[0])
     #initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
     #discard mangleName(forLoopVar)
-    let call = t.sons[1]
-    assert(len(call) in {4, 5})
-    initLocExpr(p, call.sons[1], rangeA)
-    initLocExpr(p, call.sons[2], rangeB)
+    let call = t[1]
+    assert(call.len in {4, 5})
+    initLocExpr(p, call[1], rangeA)
+    initLocExpr(p, call[2], rangeB)
 
     # $n at the beginning because of #9710
     if call.len == 4: # `||`(a, b, annotation)
@@ -633,29 +632,29 @@ proc genParForStmt(p: BProc, t: PNode) =
                           "for ($1 = $2; $1 <= $3; ++$1)",
                           [forLoopVar.loc.rdLoc,
                           rangeA.rdLoc, rangeB.rdLoc,
-                          call.sons[3].getStr.rope])
+                          call[3].getStr.rope])
     else: # `||`(a, b, step, annotation)
       var step: TLoc
-      initLocExpr(p, call.sons[3], step)
+      initLocExpr(p, call[3], step)
       lineF(p, cpsStmts, "$n#pragma omp $5$n" &
                     "for ($1 = $2; $1 <= $3; $1 += $4)",
                     [forLoopVar.loc.rdLoc,
                     rangeA.rdLoc, rangeB.rdLoc, step.rdLoc,
-                    call.sons[4].getStr.rope])
+                    call[4].getStr.rope])
 
     p.breakIdx = startBlock(p)
     p.blocks[p.breakIdx].isLoop = true
-    genStmts(p, t.sons[2])
+    genStmts(p, t[2])
     endBlock(p)
 
   dec(p.withinLoop)
 
 proc genBreakStmt(p: BProc, t: PNode) =
   var idx = p.breakIdx
-  if t.sons[0].kind != nkEmpty:
+  if t[0].kind != nkEmpty:
     # named break?
-    assert(t.sons[0].kind == nkSym)
-    var sym = t.sons[0].sym
+    assert(t[0].kind == nkSym)
+    var sym = t[0].sym
     doAssert(sym.loc.k == locOther)
     idx = sym.position-1
   else:
@@ -704,17 +703,15 @@ proc genRaiseStmt(p: BProc, t: PNode) =
 
 template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
                           rangeFormat, eqFormat: FormatStr, labl: TLabel) =
-  var
-    x, y: TLoc
-  var length = len(b)
-  for i in 0 .. length - 2:
-    if b.sons[i].kind == nkRange:
-      initLocExpr(p, b.sons[i].sons[0], x)
-      initLocExpr(p, b.sons[i].sons[1], y)
+  var x, y: TLoc
+  for i in 0..<b.len - 1:
+    if b[i].kind == nkRange:
+      initLocExpr(p, b[i][0], x)
+      initLocExpr(p, b[i][1], y)
       lineCg(p, cpsStmts, rangeFormat,
            [rdCharLoc(e), rdCharLoc(x), rdCharLoc(y), labl])
     else:
-      initLocExpr(p, b.sons[i], x)
+      initLocExpr(p, b[i], x)
       lineCg(p, cpsStmts, eqFormat, [rdCharLoc(e), rdCharLoc(x), labl])
 
 proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
@@ -724,12 +721,11 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
     # bug #4230: avoid false sharing between branches:
     if d.k == locTemp and isEmptyType(t.typ): d.k = locNone
     lineF(p, cpsStmts, "LA$1_: ;$n", [rope(labId + i)])
-    if t.sons[i].kind == nkOfBranch:
-      var length = len(t.sons[i])
-      exprBlock(p, t.sons[i].sons[length - 1], d)
+    if t[i].kind == nkOfBranch:
+      exprBlock(p, t[i][^1], d)
       lineF(p, cpsStmts, "goto $1;$n", [lend])
     else:
-      exprBlock(p, t.sons[i].sons[0], d)
+      exprBlock(p, t[i][0], d)
   result = lend
 
 template genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
@@ -740,8 +736,8 @@ template genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
   var labId = p.labels
   for i in 1..until:
     inc(p.labels)
-    if t.sons[i].kind == nkOfBranch: # else statement
-      genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat,
+    if t[i].kind == nkOfBranch: # else statement
+      genCaseGenericBranch(p, t[i], a, rangeFormat, eqFormat,
                            "LA" & rope(p.labels) & "_")
     else:
       lineF(p, cpsStmts, "goto LA$1_;$n", [rope(p.labels)])
@@ -758,38 +754,37 @@ template genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
 template genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
                     rangeFormat, eqFormat: FormatStr) =
   var a: TLoc
-  initLocExpr(p, t.sons[0], a)
-  var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, len(t)-1, a)
+  initLocExpr(p, t[0], a)
+  var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, t.len-1, a)
   fixLabel(p, lend)
 
 proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
                          branches: var openArray[Rope]) =
   var x: TLoc
-  var length = len(b)
-  for i in 0 .. length - 2:
-    assert(b.sons[i].kind != nkRange)
-    initLocExpr(p, b.sons[i], x)
-    assert(b.sons[i].kind in {nkStrLit..nkTripleStrLit})
-    var j = int(hashString(p.config, b.sons[i].strVal) and high(branches))
+  for i in 0..<b.len - 1:
+    assert(b[i].kind != nkRange)
+    initLocExpr(p, b[i], x)
+    assert(b[i].kind in {nkStrLit..nkTripleStrLit})
+    var j = int(hashString(p.config, b[i].strVal) and high(branches))
     appcg(p.module, branches[j], "if (#eqStrings($1, $2)) goto $3;$n",
          [rdLoc(e), rdLoc(x), labl])
 
 proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
   # count how many constant strings there are in the case:
   var strings = 0
-  for i in 1 ..< len(t):
-    if t.sons[i].kind == nkOfBranch: inc(strings, len(t.sons[i]) - 1)
+  for i in 1..<t.len:
+    if t[i].kind == nkOfBranch: inc(strings, t[i].len - 1)
   if strings > stringCaseThreshold:
     var bitMask = math.nextPowerOfTwo(strings) - 1
     var branches: seq[Rope]
     newSeq(branches, bitMask + 1)
     var a: TLoc
-    initLocExpr(p, t.sons[0], a) # fist pass: generate ifs+goto:
+    initLocExpr(p, t[0], a) # fist pass: generate ifs+goto:
     var labId = p.labels
-    for i in 1 ..< len(t):
+    for i in 1..<t.len:
       inc(p.labels)
-      if t.sons[i].kind == nkOfBranch:
-        genCaseStringBranch(p, t.sons[i], a, "LA" & rope(p.labels) & "_",
+      if t[i].kind == nkOfBranch:
+        genCaseStringBranch(p, t[i], a, "LA" & rope(p.labels) & "_",
                             branches)
       else:
         # else statement: nothing to do yet
@@ -797,28 +792,28 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
         discard
     linefmt(p, cpsStmts, "switch (#hashString($1) & $2) {$n",
             [rdLoc(a), bitMask])
-    for j in 0 .. high(branches):
+    for j in 0..high(branches):
       if branches[j] != nil:
         lineF(p, cpsStmts, "case $1: $n$2break;$n",
              [intLiteral(j), branches[j]])
     lineF(p, cpsStmts, "}$n", []) # else statement:
-    if t.sons[len(t)-1].kind != nkOfBranch:
+    if t[^1].kind != nkOfBranch:
       lineF(p, cpsStmts, "goto LA$1_;$n", [rope(p.labels)])
     # third pass: generate statements
-    var lend = genCaseSecondPass(p, t, d, labId, len(t)-1)
+    var lend = genCaseSecondPass(p, t, d, labId, t.len-1)
     fixLabel(p, lend)
   else:
     genCaseGeneric(p, t, d, "", "if (#eqStrings($1, $2)) goto $3;$n")
 
 proc branchHasTooBigRange(b: PNode): bool =
-  for i in 0 .. len(b)-2:
+  for i in 0..<b.len-1:
     # last son is block
-    if (b.sons[i].kind == nkRange) and
-        b.sons[i].sons[1].intVal - b.sons[i].sons[0].intVal > RangeExpandLimit:
+    if (b[i].kind == nkRange) and
+        b[i][1].intVal - b[i][0].intVal > RangeExpandLimit:
       return true
 
 proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
-  for i in 1..n.len-1:
+  for i in 1..<n.len:
     var branch = n[i]
     var stmtBlock = lastSon(branch)
     if stmtBlock.stmtsContainPragma(wLinearScanEnd):
@@ -828,8 +823,7 @@ proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
         result = i
 
 proc genCaseRange(p: BProc, branch: PNode) =
-  var length = branch.len
-  for j in 0 .. length-2:
+  for j in 0..<branch.len-1:
     if branch[j].kind == nkRange:
       if hasSwitchRange in CC[p.config.cCompiler].props:
         lineF(p, cpsStmts, "case $1 ... $2:$n", [
@@ -849,7 +843,7 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
 
   # generate if part (might be empty):
   var a: TLoc
-  initLocExpr(p, n.sons[0], a)
+  initLocExpr(p, n[0], a)
   var lend = if splitPoint > 0: genIfForCaseUntil(p, n, d,
                     rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n",
                     eqFormat = "if ($1 == $2) goto $3;$n",
@@ -859,7 +853,7 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
   if splitPoint+1 < n.len:
     lineF(p, cpsStmts, "switch ($1) {$n", [rdCharLoc(a)])
     var hasDefault = false
-    for i in splitPoint+1 ..< n.len:
+    for i in splitPoint+1..<n.len:
       # bug #4230: avoid false sharing between branches:
       if d.k == locTemp and isEmptyType(n.typ): d.k = locNone
       var branch = n[i]
@@ -880,14 +874,14 @@ proc genCase(p: BProc, t: PNode, d: var TLoc) =
   genLineDir(p, t)
   if not isEmptyType(t.typ) and d.k == locNone:
     getTemp(p, t.typ, d)
-  case skipTypes(t.sons[0].typ, abstractVarRange).kind
+  case skipTypes(t[0].typ, abstractVarRange).kind
   of tyString:
     genStringCase(p, t, d)
   of tyFloat..tyFloat128:
     genCaseGeneric(p, t, d, "if ($1 >= $2 && $1 <= $3) goto $4;$n",
                             "if ($1 == $2) goto $3;$n")
   else:
-    if t.sons[0].kind == nkSym and sfGoto in t.sons[0].sym.flags:
+    if t[0].kind == nkSym and sfGoto in t[0].sym.flags:
       genGotoForCase(p, t)
     else:
       genOrdinalCase(p, t, d)
@@ -926,7 +920,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
   genLineDir(p, t)
   discard cgsym(p.module, "popCurrentExceptionEx")
   let fin = if t[^1].kind == nkFinally: t[^1] else: nil
-  add(p.nestedTryStmts, (fin, false))
+  p.nestedTryStmts.add((fin, false))
   startBlock(p, "try {$n")
   expr(p, t[0], d)
   endBlock(p)
@@ -947,7 +941,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
       genExceptBranchBody(t[i][0])
       endBlock(p)
     else:
-      for j in 0..t[i].len-2:
+      for j in 0..<t[i].len-1:
         if t[i][j].isInfixAs():
           let exvar = t[i][j][2] # ex1 in `except ExceptType as ex1:`
           fillLoc(exvar.sym.loc, locTemp, exvar, mangleLocalName(p, exvar.sym), OnUnknown)
@@ -1023,40 +1017,38 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
     else:
       linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
     startBlock(p, "if ($1.status == 0) {$n", [safePoint])
-  let length = len(t)
   let fin = if t[^1].kind == nkFinally: t[^1] else: nil
-  add(p.nestedTryStmts, (fin, quirkyExceptions))
-  expr(p, t.sons[0], d)
+  p.nestedTryStmts.add((fin, quirkyExceptions))
+  expr(p, t[0], d)
   if not quirkyExceptions:
     linefmt(p, cpsStmts, "#popSafePoint();$n", [])
     endBlock(p)
     startBlock(p, "else {$n")
     linefmt(p, cpsStmts, "#popSafePoint();$n", [])
     genRestoreFrameAfterException(p)
-  elif 1 < length and t.sons[1].kind == nkExceptBranch:
+  elif 1 < t.len and t[1].kind == nkExceptBranch:
     startBlock(p, "if (#getCurrentException()) {$n")
   else:
     startBlock(p)
   p.nestedTryStmts[^1].inExcept = true
   var i = 1
-  while (i < length) and (t.sons[i].kind == nkExceptBranch):
+  while (i < t.len) and (t[i].kind == nkExceptBranch):
     # bug #4230: avoid false sharing between branches:
     if d.k == locTemp and isEmptyType(t.typ): d.k = locNone
-    var blen = len(t.sons[i])
-    if blen == 1:
+    if t[i].len == 1:
       # general except section:
       if i > 1: lineF(p, cpsStmts, "else", [])
       startBlock(p)
       if not quirkyExceptions:
         linefmt(p, cpsStmts, "$1.status = 0;$n", [safePoint])
-      expr(p, t.sons[i].sons[0], d)
+      expr(p, t[i][0], d)
       linefmt(p, cpsStmts, "#popCurrentException();$n", [])
       endBlock(p)
     else:
       var orExpr: Rope = nil
-      for j in 0 .. blen - 2:
-        assert(t.sons[i].sons[j].kind == nkType)
-        if orExpr != nil: add(orExpr, "||")
+      for j in 0..<t[i].len - 1:
+        assert(t[i][j].kind == nkType)
+        if orExpr != nil: orExpr.add("||")
         let checkFor = if optTinyRtti in p.config.globalOptions:
           genTypeInfo2Name(p.module, t[i][j].typ)
         else:
@@ -1068,15 +1060,15 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
       startBlock(p, "if ($1) {$n", [orExpr])
       if not quirkyExceptions:
         linefmt(p, cpsStmts, "$1.status = 0;$n", [safePoint])
-      expr(p, t.sons[i].sons[blen-1], d)
+      expr(p, t[i][^1], d)
       linefmt(p, cpsStmts, "#popCurrentException();$n", [])
       endBlock(p)
     inc(i)
   discard pop(p.nestedTryStmts)
   endBlock(p) # end of else block
-  if i < length and t.sons[i].kind == nkFinally:
+  if i < t.len and t[i].kind == nkFinally:
     p.finallySafePoints.add(safePoint)
-    genSimpleBlock(p, t.sons[i].sons[0])
+    genSimpleBlock(p, t[i][0])
     discard pop(p.finallySafePoints)
   if not quirkyExceptions:
     linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint])
@@ -1120,12 +1112,12 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
         if x[j] in {'"', ':'}:
           # don't modify the line if already in quotes or
           # some clobber register list:
-          add(result, x); add(result, "\L")
+          result.add(x); result.add("\L")
         else:
           # ignore empty lines
-          add(result, "\"")
-          add(result, x)
-          add(result, "\\n\"\n")
+          result.add("\"")
+          result.add(x)
+          result.add("\\n\"\n")
   else:
     res.add("\L")
     result = res.rope
@@ -1139,25 +1131,25 @@ proc genAsmStmt(p: BProc, t: PNode) =
   # work:
   if p.prc == nil:
     # top level asm statement?
-    add(p.module.s[cfsProcHeaders], runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s]))
+    p.module.s[cfsProcHeaders].add runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s])
   else:
-    add(p.s(cpsStmts), indentLine(p, runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s])))
+    p.s(cpsStmts).add indentLine(p, runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s]))
 
 proc determineSection(n: PNode): TCFileSection =
   result = cfsProcHeaders
-  if n.len >= 1 and n.sons[0].kind in {nkStrLit..nkTripleStrLit}:
-    let sec = n.sons[0].strVal
+  if n.len >= 1 and n[0].kind in {nkStrLit..nkTripleStrLit}:
+    let sec = n[0].strVal
     if sec.startsWith("/*TYPESECTION*/"): result = cfsTypes
     elif sec.startsWith("/*VARSECTION*/"): result = cfsVars
     elif sec.startsWith("/*INCLUDESECTION*/"): result = cfsHeaders
 
 proc genEmit(p: BProc, t: PNode) =
-  var s = genAsmOrEmitStmt(p, t.sons[1])
+  var s = genAsmOrEmitStmt(p, t[1])
   if p.prc == nil:
     # top level emit pragma?
     let section = determineSection(t[1])
     genCLineDir(p.module.s[section], t.info, p.config)
-    add(p.module.s[section], s)
+    p.module.s[section].add(s)
   else:
     genLineDir(p, t)
     line(p, cpsStmts, s)
@@ -1169,18 +1161,18 @@ proc genPragma(p: BProc, n: PNode) =
     of wInjectStmt:
       var p = newProc(nil, p.module)
       p.options = p.options - {optLineTrace, optStackTrace}
-      genStmts(p, it.sons[1])
+      genStmts(p, it[1])
       p.module.injectStmt = p.s(cpsStmts)
     else: discard
 
 proc fieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =
   if optFieldCheck in p.options:
-    var le = asgn.sons[0]
+    var le = asgn[0]
     if le.kind == nkCheckedFieldExpr:
-      var field = le.sons[0].sons[1].sym
+      var field = le[0][1].sym
       result = sfDiscriminant in field.flags
     elif le.kind == nkDotExpr:
-      var field = le.sons[1].sym
+      var field = le[1].sym
       result = sfDiscriminant in field.flags
 
 proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
@@ -1188,14 +1180,13 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
   var t = skipTypes(objtype, abstractVar)
   assert t.kind == tyObject
   discard genTypeInfo(p.module, t, a.lode.info)
-  var L = toInt64(lengthOrd(p.config, field.typ))
   if not containsOrIncl(p.module.declaredThings, field.id):
     appcg(p.module, cfsVars, "extern $1",
           [discriminatorTableDecl(p.module, t, field)])
   lineCg(p, cpsStmts,
         "#FieldDiscriminantCheck((NI)(NU)($1), (NI)(NU)($2), $3, $4);$n",
         [rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field),
-         intLiteral(L+1)])
+         intLiteral(toInt64(lengthOrd(p.config, field.typ))+1)])
 
 proc genCaseObjDiscMapping(p: BProc, e: PNode, t: PType, field: PSym; d: var TLoc) =
   const ObjDiscMappingProcSlot = -5
@@ -1214,12 +1205,12 @@ proc genCaseObjDiscMapping(p: BProc, e: PNode, t: PType, field: PSym; d: var TLo
 
 proc asgnFieldDiscriminant(p: BProc, e: PNode) =
   var a, tmp: TLoc
-  var dotExpr = e.sons[0]
-  if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr.sons[0]
-  initLocExpr(p, e.sons[0], a)
+  var dotExpr = e[0]
+  if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr[0]
+  initLocExpr(p, e[0], a)
   getTemp(p, a.t, tmp)
-  expr(p, e.sons[1], tmp)
-  let field = dotExpr.sons[1].sym
+  expr(p, e[1], tmp)
+  let field = dotExpr[1].sym
   if optTinyRtti in p.config.globalOptions:
     let t = dotExpr[0].typ.skipTypes(abstractInst)
     var oldVal, newVal: TLoc
@@ -1229,13 +1220,13 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
           "#nimFieldDiscriminantCheckV2($1, $2);$n",
           [rdLoc(oldVal), rdLoc(newVal)])
   else:
-    genDiscriminantCheck(p, a, tmp, dotExpr.sons[0].typ, field)
+    genDiscriminantCheck(p, a, tmp, dotExpr[0].typ, field)
   genAssignment(p, a, tmp, {})
 
 proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
-  if e.sons[0].kind == nkSym and sfGoto in e.sons[0].sym.flags:
+  if e[0].kind == nkSym and sfGoto in e[0].sym.flags:
     genLineDir(p, e)
-    genGotoVar(p, e.sons[1])
+    genGotoVar(p, e[1])
   elif not fieldDiscriminantCheckNeeded(p, e):
     let le = e[0]
     let ri = e[1]
diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim
index d2d4ada36..7586aa865 100644
--- a/compiler/ccgthreadvars.nim
+++ b/compiler/ccgthreadvars.nim
@@ -19,8 +19,8 @@ proc accessThreadLocalVar(p: BProc, s: PSym) =
   if emulatedThreadVars(p.config) and not p.threadVarAccessed:
     p.threadVarAccessed = true
     incl p.module.flags, usesThreadVars
-    addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV_;$n", [])
-    add(p.procSec(cpsInit),
+    p.procSec(cpsLocals).addf("\tNimThreadVars* NimTV_;$n", [])
+    p.procSec(cpsInit).add(
       ropecg(p.module, "\tNimTV_ = (NimThreadVars*) #GetThreadLocalVars();$n", []))
 
 proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
@@ -30,23 +30,23 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
     # allocator for it :-(
     if not containsOrIncl(m.g.nimtvDeclared, s.id):
       m.g.nimtvDeps.add(s.loc.t)
-      addf(m.g.nimtv, "$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.r])
+      m.g.nimtv.addf("$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.r])
   else:
-    if isExtern: add(m.s[cfsVars], "extern ")
-    if optThreads in m.config.globalOptions: add(m.s[cfsVars], "NIM_THREADVAR ")
-    add(m.s[cfsVars], getTypeDesc(m, s.loc.t))
-    addf(m.s[cfsVars], " $1;$n", [s.loc.r])
+    if isExtern: m.s[cfsVars].add("extern ")
+    if optThreads in m.config.globalOptions: m.s[cfsVars].add("NIM_THREADVAR ")
+    m.s[cfsVars].add(getTypeDesc(m, s.loc.t))
+    m.s[cfsVars].addf(" $1;$n", [s.loc.r])
 
 proc generateThreadLocalStorage(m: BModule) =
   if m.g.nimtv != nil and (usesThreadVars in m.flags or sfMainModule in m.module.flags):
     for t in items(m.g.nimtvDeps): discard getTypeDesc(m, t)
-    addf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [m.g.nimtv])
+    m.s[cfsSeqTypes].addf("typedef struct {$1} NimThreadVars;$n", [m.g.nimtv])
 
 proc generateThreadVarsSize(m: BModule) =
   if m.g.nimtv != nil:
     let externc = if m.config.cmd == cmdCompileToCpp or
                        sfCompileToCpp in m.module.flags: "extern \"C\" "
                   else: ""
-    addf(m.s[cfsProcs],
+    m.s[cfsProcs].addf(
       "$#NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}$n",
       [externc.rope])
diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim
index e494b3e48..a0048a769 100644
--- a/compiler/ccgtrav.nim
+++ b/compiler/ccgtrav.nim
@@ -28,18 +28,18 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
   if n == nil: return
   case n.kind
   of nkRecList:
-    for i in 0 ..< len(n):
-      genTraverseProc(c, accessor, n.sons[i], typ)
+    for i in 0..<n.len:
+      genTraverseProc(c, accessor, n[i], typ)
   of nkRecCase:
-    if (n.sons[0].kind != nkSym): internalError(c.p.config, n.info, "genTraverseProc")
+    if (n[0].kind != nkSym): internalError(c.p.config, n.info, "genTraverseProc")
     var p = c.p
-    let disc = n.sons[0].sym
+    let disc = n[0].sym
     if disc.loc.r == nil: fillObjectFields(c.p.module, typ)
     if disc.loc.t == nil:
       internalError(c.p.config, n.info, "genTraverseProc()")
     lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r])
-    for i in 1 ..< len(n):
-      let branch = n.sons[i]
+    for i in 1..<n.len:
+      let branch = n[i]
       assert branch.kind in {nkOfBranch, nkElse}
       if branch.kind == nkOfBranch:
         genCaseRange(c.p, branch)
@@ -73,29 +73,29 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
      tySink, tyOwned:
     genTraverseProc(c, accessor, lastSon(typ))
   of tyArray:
-    let arraySize = lengthOrd(c.p.config, typ.sons[0])
+    let arraySize = lengthOrd(c.p.config, typ[0])
     var i: TLoc
     getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo(), tyInt), i)
     let oldCode = p.s(cpsStmts)
     linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
             [i.r, arraySize])
     let oldLen = p.s(cpsStmts).len
-    genTraverseProc(c, ropecg(c.p.module, "$1[$2]", [accessor, i.r]), typ.sons[1])
+    genTraverseProc(c, ropecg(c.p.module, "$1[$2]", [accessor, i.r]), typ[1])
     if p.s(cpsStmts).len == oldLen:
       # do not emit dummy long loops for faster debug builds:
       p.s(cpsStmts) = oldCode
     else:
       lineF(p, cpsStmts, "}$n", [])
   of tyObject:
-    for i in 0 ..< len(typ):
-      var x = typ.sons[i]
+    for i in 0..<typ.len:
+      var x = typ[i]
       if x != nil: x = x.skipTypes(skipPtrs)
       genTraverseProc(c, accessor.parentObj(c.p.module), x)
     if typ.n != nil: genTraverseProc(c, accessor, typ.n, typ)
   of tyTuple:
     let typ = getUniqueType(typ)
-    for i in 0 ..< len(typ):
-      genTraverseProc(c, ropecg(c.p.module, "$1.Field$2", [accessor, i]), typ.sons[i])
+    for i in 0..<typ.len:
+      genTraverseProc(c, ropecg(c.p.module, "$1.Field$2", [accessor, i]), typ[i])
   of tyRef:
     lineCg(p, cpsStmts, visitorFrmt, [accessor, c.visitorFrmt])
   of tySequence:
@@ -127,7 +127,7 @@ proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
   lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
       [i.r, lenExpr(c.p, a)])
   let oldLen = p.s(cpsStmts).len
-  genTraverseProc(c, "$1$3[$2]" % [accessor, i.r, dataField(c.p)], typ.sons[0])
+  genTraverseProc(c, "$1$3[$2]" % [accessor, i.r, dataField(c.p)], typ[0])
   if p.s(cpsStmts).len == oldLen:
     # do not emit dummy long loops for faster debug builds:
     p.s(cpsStmts) = oldCode
@@ -155,11 +155,11 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
   if typ.kind == tySequence:
     genTraverseProcSeq(c, "a".rope, typ)
   else:
-    if skipTypes(typ.sons[0], typedescInst+{tyOwned}).kind == tyArray:
+    if skipTypes(typ[0], typedescInst+{tyOwned}).kind == tyArray:
       # C's arrays are broken beyond repair:
-      genTraverseProc(c, "a".rope, typ.sons[0])
+      genTraverseProc(c, "a".rope, typ[0])
     else:
-      genTraverseProc(c, "(*a)".rope, typ.sons[0])
+      genTraverseProc(c, "(*a)".rope, typ[0])
 
   let generatedProc = "$1 {$n$2$3$4}\n" %
         [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
@@ -168,8 +168,8 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
   m.s[cfsProcs].add(generatedProc)
 
   if hcrOn:
-    addf(m.s[cfsProcHeaders], "N_NIMCALL_PTR(void, $1)(void*, NI);\n", [result])
-    addf(m.s[cfsDynLibInit], "\t$1 = (N_NIMCALL_PTR(void, )(void*, NI)) hcrRegisterProc($3, \"$1\", (void*)$2);\n",
+    m.s[cfsProcHeaders].addf("N_NIMCALL_PTR(void, $1)(void*, NI);\n", [result])
+    m.s[cfsDynLibInit].addf("\t$1 = (N_NIMCALL_PTR(void, )(void*, NI)) hcrRegisterProc($3, \"$1\", (void*)$2);\n",
          [result, markerName, getModuleDllPath(m)])
 
 proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope =
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 9f2dc1633..c2e8e6883 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -48,7 +48,7 @@ proc mangleName(m: BModule; s: PSym): Rope =
   result = s.loc.r
   if result == nil:
     result = s.name.s.mangle.rope
-    add(result, idOrSig(s, m.module.name.s.mangle, m.sigConflicts))
+    result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts))
     s.loc.r = result
     writeMangledName(m.ndi, s, m.config)
 
@@ -175,7 +175,7 @@ proc mapType(conf: ConfigRef; typ: PType): TCTypeKind =
       of 4: result = ctInt32
       of 8: result = ctInt64
       else: result = ctInt32
-  of tyRange: result = mapType(conf, typ.sons[0])
+  of tyRange: result = mapType(conf, typ[0])
   of tyPtr, tyVar, tyLent, tyRef:
     var base = skipTypes(typ.lastSon, typedescInst)
     case base.kind
@@ -213,7 +213,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope
 
 proc isObjLackingTypeField(typ: PType): bool {.inline.} =
   result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
-      (typ.sons[0] == nil) or isPureObject(typ))
+      (typ[0] == nil) or isPureObject(typ))
 
 proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool =
   # Arrays and sets cannot be returned by a C procedure, because C is
@@ -248,7 +248,7 @@ proc cacheGetType(tab: TypeCache; sig: SigHash): Rope =
 
 proc addAbiCheck(m: BModule, t: PType, name: Rope) =
   if isDefined(m.config, "checkabi") and (let size = getSize(m.config, t); size != szUnknownSize):
-    addf(m.s[cfsTypeInfo], "NIM_CHECK_SIZE($1, $2);$n", [name, rope(size)])
+    m.s[cfsTypeInfo].addf("NIM_CHECK_SIZE($1, $2);$n", [name, rope(size)])
 
 proc ccgIntroducedPtr(conf: ConfigRef; s: PSym, retType: PType): bool =
   var pt = skipTypes(s.typ, typedescInst)
@@ -265,7 +265,7 @@ proc ccgIntroducedPtr(conf: ConfigRef; s: PSym, retType: PType): bool =
       result = true           # requested anyway
     elif retType != nil and retType.kind == tyLent:
       result = true
-    elif (tfFinal in pt.flags) and (pt.sons[0] == nil):
+    elif (tfFinal in pt.flags) and (pt[0] == nil):
       result = false          # no need, because no subtyping possible
     else:
       result = true           # ordinary objects are always passed by reference,
@@ -316,7 +316,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
   of tyNil: result = typeNameOrLiteral(m, typ, "void*")
   of tyInt..tyUInt64:
     result = typeNameOrLiteral(m, typ, NumericalTypeToStr[typ.kind])
-  of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0])
+  of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ[0])
   of tyStatic:
     if typ.n != nil: result = getSimpleTypeDesc(m, lastSon typ)
     else: internalError(m.config, "tyStatic for getSimpleTypeDesc")
@@ -331,10 +331,10 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
       addAbiCheck(m, typ, result)
 
 proc pushType(m: BModule, typ: PType) =
-  for i in 0 .. high(m.typeStack):
+  for i in 0..high(m.typeStack):
     # pointer equality is good enough here:
     if m.typeStack[i] == typ: return
-  add(m.typeStack, typ)
+  m.typeStack.add(typ)
 
 proc getTypePre(m: BModule, typ: PType; sig: SigHash): Rope =
   if typ == nil: result = rope("void")
@@ -391,7 +391,7 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
   of tySequence:
     let sig = hashType(t)
     if optSeqDestructors in m.config.globalOptions:
-      if skipTypes(etB.sons[0], typedescInst).kind == tyEmpty:
+      if skipTypes(etB[0], typedescInst).kind == tyEmpty:
         internalError(m.config, "cannot map the empty seq type to a C type")
 
       result = cacheGetType(m.forwTypeCache, sig)
@@ -434,7 +434,7 @@ $3ifndef $2_Content_PP
 $3define $2_Content_PP
 struct $2_Content { NI cap;#AllocatorObj* allocator;$1 data[SEQ_DECL_SIZE];};
 $3endif$N
-      """, [getTypeDescAux(m, t.skipTypes(abstractInst).sons[0], check), result, rope"#"])
+      """, [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check), result, rope"#"])
 
 proc paramStorageLoc(param: PSym): TStorageLoc =
   if param.typ.skipTypes({tyVar, tyLent, tyTypeDesc}).kind notin {
@@ -447,28 +447,28 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
                    check: var IntSet, declareEnvironment=true;
                    weakDep=false) =
   params = nil
-  if t.sons[0] == nil or isInvalidReturnType(m.config, t.sons[0]):
+  if t[0] == nil or isInvalidReturnType(m.config, t[0]):
     rettype = ~"void"
   else:
-    rettype = getTypeDescAux(m, t.sons[0], check)
-  for i in 1 ..< len(t.n):
-    if t.n.sons[i].kind != nkSym: internalError(m.config, t.n.info, "genProcParams")
-    var param = t.n.sons[i].sym
+    rettype = getTypeDescAux(m, t[0], check)
+  for i in 1..<t.n.len:
+    if t.n[i].kind != nkSym: internalError(m.config, t.n.info, "genProcParams")
+    var param = t.n[i].sym
     if isCompileTimeOnly(param.typ): continue
-    if params != nil: add(params, ~", ")
-    fillLoc(param.loc, locParam, t.n.sons[i], mangleParamName(m, param),
+    if params != nil: params.add(~", ")
+    fillLoc(param.loc, locParam, t.n[i], mangleParamName(m, param),
             param.paramStorageLoc)
-    if ccgIntroducedPtr(m.config, param, t.sons[0]):
-      add(params, getTypeDescWeak(m, param.typ, check))
-      add(params, ~"*")
+    if ccgIntroducedPtr(m.config, param, t[0]):
+      params.add(getTypeDescWeak(m, param.typ, check))
+      params.add(~"*")
       incl(param.loc.flags, lfIndirect)
       param.loc.storage = OnUnknown
     elif weakDep:
-      add(params, getTypeDescWeak(m, param.typ, check))
+      params.add(getTypeDescWeak(m, param.typ, check))
     else:
-      add(params, getTypeDescAux(m, param.typ, check))
-    add(params, ~" ")
-    add(params, param.loc.r)
+      params.add(getTypeDescAux(m, param.typ, check))
+    params.add(~" ")
+    params.add(param.loc.r)
     # declare the len field for open arrays:
     var arr = param.typ
     if arr.kind in {tyVar, tyLent, tySink}: arr = arr.lastSon
@@ -477,26 +477,26 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
       # this fixes the 'sort' bug:
       if param.typ.kind in {tyVar, tyLent}: param.loc.storage = OnUnknown
       # need to pass hidden parameter:
-      addf(params, ", NI $1Len_$2", [param.loc.r, j.rope])
+      params.addf(", NI $1Len_$2", [param.loc.r, j.rope])
       inc(j)
-      arr = arr.sons[0].skipTypes({tySink})
-  if t.sons[0] != nil and isInvalidReturnType(m.config, t.sons[0]):
-    var arr = t.sons[0]
-    if params != nil: add(params, ", ")
-    if mapReturnType(m.config, t.sons[0]) != ctArray:
-      add(params, getTypeDescWeak(m, arr, check))
-      add(params, "*")
+      arr = arr[0].skipTypes({tySink})
+  if t[0] != nil and isInvalidReturnType(m.config, t[0]):
+    var arr = t[0]
+    if params != nil: params.add(", ")
+    if mapReturnType(m.config, t[0]) != ctArray:
+      params.add(getTypeDescWeak(m, arr, check))
+      params.add("*")
     else:
-      add(params, getTypeDescAux(m, arr, check))
-    addf(params, " Result", [])
+      params.add(getTypeDescAux(m, arr, check))
+    params.addf(" Result", [])
   if t.callConv == ccClosure and declareEnvironment:
-    if params != nil: add(params, ", ")
-    add(params, "void* ClE_0")
+    if params != nil: params.add(", ")
+    params.add("void* ClE_0")
   if tfVarargs in t.flags:
-    if params != nil: add(params, ", ")
-    add(params, "...")
-  if params == nil: add(params, "void)")
-  else: add(params, ")")
+    if params != nil: params.add(", ")
+    params.add("...")
+  if params == nil: params.add("void)")
+  else: params.add(")")
   params = "(" & params
 
 proc mangleRecFieldName(m: BModule; field: PSym): Rope =
@@ -512,37 +512,37 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
   result = nil
   case n.kind
   of nkRecList:
-    for i in 0 ..< len(n):
-      add(result, genRecordFieldsAux(m, n.sons[i], rectype, check))
+    for i in 0..<n.len:
+      result.add(genRecordFieldsAux(m, n[i], rectype, check))
   of nkRecCase:
-    if n.sons[0].kind != nkSym: internalError(m.config, n.info, "genRecordFieldsAux")
-    add(result, genRecordFieldsAux(m, n.sons[0], rectype, check))
+    if n[0].kind != nkSym: internalError(m.config, n.info, "genRecordFieldsAux")
+    result.add(genRecordFieldsAux(m, n[0], rectype, check))
     # prefix mangled name with "_U" to avoid clashes with other field names,
     # since identifiers are not allowed to start with '_'
     var unionBody: Rope = nil
-    for i in 1 ..< len(n):
-      case n.sons[i].kind
+    for i in 1..<n.len:
+      case n[i].kind
       of nkOfBranch, nkElse:
-        let k = lastSon(n.sons[i])
+        let k = lastSon(n[i])
         if k.kind != nkSym:
           let a = genRecordFieldsAux(m, k, rectype, check)
           if a != nil:
             if tfPacked notin rectype.flags:
-              add(unionBody, "struct {")
+              unionBody.add("struct {")
             else:
               if hasAttribute in CC[m.config.cCompiler].props:
-                add(unionBody, "struct __attribute__((__packed__)){" )
+                unionBody.add("struct __attribute__((__packed__)){" )
               else:
-                addf(unionBody, "#pragma pack(push, 1)$nstruct{", [])
-            add(unionBody, a)
-            addf(unionBody, "};$n", [])
+                unionBody.addf("#pragma pack(push, 1)$nstruct{", [])
+            unionBody.add(a)
+            unionBody.addf("};$n", [])
             if tfPacked in rectype.flags and hasAttribute notin CC[m.config.cCompiler].props:
-              addf(unionBody, "#pragma pack(pop)$n", [])
+              unionBody.addf("#pragma pack(pop)$n", [])
         else:
-          add(unionBody, genRecordFieldsAux(m, k, rectype, check))
+          unionBody.add(genRecordFieldsAux(m, k, rectype, check))
       else: internalError(m.config, "genRecordFieldsAux(record case branch)")
     if unionBody != nil:
-      addf(result, "union{$n$1};$n", [unionBody])
+      result.addf("union{$n$1};$n", [unionBody])
   of nkSym:
     let field = n.sym
     if field.typ.kind == tyVoid: return
@@ -557,17 +557,17 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
     if not isImportedCppType(rectype):
       let fieldType = field.loc.lode.typ.skipTypes(abstractInst)
       if fieldType.kind == tyUncheckedArray:
-        addf(result, "$1 $2[SEQ_DECL_SIZE];$n",
+        result.addf("$1 $2[SEQ_DECL_SIZE];$n",
             [getTypeDescAux(m, fieldType.elemType, check), sname])
       elif fieldType.kind == tySequence:
         # we need to use a weak dependency here for trecursive_table.
-        addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
+        result.addf("$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
       elif field.bitsize != 0:
-        addf(result, "$1 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check), sname, rope($field.bitsize)])
+        result.addf("$1 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check), sname, rope($field.bitsize)])
       else:
         # don't use fieldType here because we need the
         # tyGenericInst for C++ template support
-        addf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
+        result.addf("$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
   else: internalError(m.config, n.info, "genRecordFieldsAux()")
 
 proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope =
@@ -599,7 +599,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
 
   if typ.kind == tyObject:
 
-    if typ.sons[0] == nil:
+    if typ[0] == nil:
       if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags:
         appcg(m, result, " {$n", [])
       else:
@@ -607,7 +607,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
         hasField = true
     elif m.compileToCpp:
       appcg(m, result, " : public $1 {$n",
-                      [getTypeDescAux(m, typ.sons[0].skipTypes(skipPtrs), check)])
+                      [getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check)])
       if typ.isException:
         appcg(m, result, "virtual void raise() { throw *this; }$n", []) # required for polymorphic exceptions
         if typ.sym.magic == mException:
@@ -619,17 +619,17 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
       hasField = true
     else:
       appcg(m, result, " {$n  $1 Sup;$n",
-                      [getTypeDescAux(m, typ.sons[0].skipTypes(skipPtrs), check)])
+                      [getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check)])
       hasField = true
   else:
-    addf(result, " {$n", [name])
+    result.addf(" {$n", [name])
 
   let desc = getRecordFields(m, typ, check)
   if desc == nil and not hasField:
-    addf(result, "char dummy;$n", [])
+    result.addf("char dummy;$n", [])
   else:
-    add(result, desc)
-  add(result, "};\L")
+    result.add(desc)
+  result.add("};\L")
   if tfPacked in typ.flags and hasAttribute notin CC[m.config.cCompiler].props:
     result.add "#pragma pack(pop)\L"
 
@@ -637,12 +637,12 @@ proc getTupleDesc(m: BModule, typ: PType, name: Rope,
                   check: var IntSet): Rope =
   result = "$1 $2 {$n" % [structOrUnion(typ), name]
   var desc: Rope = nil
-  for i in 0 ..< len(typ):
-    addf(desc, "$1 Field$2;$n",
-         [getTypeDescAux(m, typ.sons[i], check), rope(i)])
-  if desc == nil: add(result, "char dummy;\L")
-  else: add(result, desc)
-  add(result, "};\L")
+  for i in 0..<typ.len:
+    desc.addf("$1 Field$2;$n",
+         [getTypeDescAux(m, typ[i], check), rope(i)])
+  if desc == nil: result.add("char dummy;\L")
+  else: result.add(desc)
+  result.add("};\L")
 
 proc scanCppGenericSlot(pat: string, cursor, outIdx, outStars: var int): bool =
   # A helper proc for handling cppimport patterns, involving numeric
@@ -667,10 +667,10 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
   if idx >= typ.len:
     doAssert false, "invalid apostrophe type parameter index"
 
-  result = typ.sons[idx]
+  result = typ[idx]
   for i in 1..stars:
     if result != nil and result.len > 0:
-      result = if result.kind == tyGenericInst: result.sons[1]
+      result = if result.kind == tyGenericInst: result[1]
                else: result.elemType
 
 proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
@@ -726,7 +726,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
       result = getTypeDescAux(m, et, check) & star
       m.typeCache[sig] = result
   of tyOpenArray, tyVarargs:
-    result = getTypeDescWeak(m, t.sons[0], check) & "*"
+    result = getTypeDescWeak(m, t[0], check) & "*"
     m.typeCache[sig] = result
   of tyEnum:
     result = cacheGetType(m.typeCache, sig)
@@ -737,23 +737,23 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
         m.typeCache[sig] = result
         var size: int
         if firstOrd(m.config, t) < 0:
-          addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result])
+          m.s[cfsTypes].addf("typedef NI32 $1;$n", [result])
           size = 4
         else:
           size = int(getSize(m.config, t))
           case size
-          of 1: addf(m.s[cfsTypes], "typedef NU8 $1;$n", [result])
-          of 2: addf(m.s[cfsTypes], "typedef NU16 $1;$n", [result])
-          of 4: addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result])
-          of 8: addf(m.s[cfsTypes], "typedef NI64 $1;$n", [result])
+          of 1: m.s[cfsTypes].addf("typedef NU8 $1;$n", [result])
+          of 2: m.s[cfsTypes].addf("typedef NU16 $1;$n", [result])
+          of 4: m.s[cfsTypes].addf("typedef NI32 $1;$n", [result])
+          of 8: m.s[cfsTypes].addf("typedef NI64 $1;$n", [result])
           else: internalError(m.config, t.sym.info, "getTypeDescAux: enum")
         when false:
           let owner = hashOwner(t.sym)
           if not gDebugInfo.hasEnum(t.sym.name.s, t.sym.info.line, owner):
             var vals: seq[(string, int)] = @[]
-            for i in 0 ..< t.n.len:
-              assert(t.n.sons[i].kind == nkSym)
-              let field = t.n.sons[i].sym
+            for i in 0..<t.n.len:
+              assert(t.n[i].kind == nkSym)
+              let field = t.n[i].sym
               vals.add((field.name.s, field.position.int))
             gDebugInfo.registerEnum(EnumDesc(size: size, owner: owner, id: t.sym.id,
               name: t.sym.name.s, values: vals))
@@ -764,10 +764,10 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
     genProcParams(m, t, rettype, desc, check, true, true)
     if not isImportedType(t):
       if t.callConv != ccClosure: # procedure vars may need a closure!
-        addf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n",
+        m.s[cfsTypes].addf("typedef $1_PTR($2, $3) $4;$n",
              [rope(CallingConvToStr[t.callConv]), rettype, result, desc])
       else:
-        addf(m.s[cfsTypes], "typedef struct {$n" &
+        m.s[cfsTypes].addf("typedef struct {$n" &
             "N_NIMCALL_PTR($2, ClP_0) $3;$n" &
             "void* ClE_0;$n} $1;$n",
              [result, rettype, desc])
@@ -786,7 +786,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
       assert(cacheGetType(m.typeCache, sig) == nil)
       m.typeCache[sig] = result & seqStar(m)
       if not isImportedType(t):
-        if skipTypes(t.sons[0], typedescInst).kind != tyEmpty:
+        if skipTypes(t[0], typedescInst).kind != tyEmpty:
           const
             cppSeq = "struct $2 : #TGenericSeq {$n"
             cSeq = "struct $2 {$n" &
@@ -794,28 +794,28 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
           if m.compileToCpp:
             appcg(m, m.s[cfsSeqTypes],
                 cppSeq & "  $1 data[SEQ_DECL_SIZE];$n" &
-                "};$n", [getTypeDescAux(m, t.sons[0], check), result])
+                "};$n", [getTypeDescAux(m, t[0], check), result])
           else:
             appcg(m, m.s[cfsSeqTypes],
                 cSeq & "  $1 data[SEQ_DECL_SIZE];$n" &
-                "};$n", [getTypeDescAux(m, t.sons[0], check), result])
+                "};$n", [getTypeDescAux(m, t[0], check), result])
         else:
           result = rope("TGenericSeq")
-      add(result, seqStar(m))
+      result.add(seqStar(m))
   of tyUncheckedArray:
     result = getTypeName(m, origTyp, sig)
     m.typeCache[sig] = result
     if not isImportedType(t):
-      let foo = getTypeDescAux(m, t.sons[0], check)
-      addf(m.s[cfsTypes], "typedef $1 $2[1];$n", [foo, result])
+      let foo = getTypeDescAux(m, t[0], check)
+      m.s[cfsTypes].addf("typedef $1 $2[1];$n", [foo, result])
   of tyArray:
     var n: BiggestInt = toInt64(lengthOrd(m.config, t))
     if n <= 0: n = 1   # make an array of at least one element
     result = getTypeName(m, origTyp, sig)
     m.typeCache[sig] = result
     if not isImportedType(t):
-      let foo = getTypeDescAux(m, t.sons[1], check)
-      addf(m.s[cfsTypes], "typedef $1 $2[$3];$n",
+      let foo = getTypeDescAux(m, t[1], check)
+      m.s[cfsTypes].addf("typedef $1 $2[$3];$n",
            [foo, result, rope(n)])
     else: addAbiCheck(m, t, result)
   of tyObject, tyTuple:
@@ -850,9 +850,9 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
         result.add cppName.data.substr(chunkStart)
       else:
         result = cppName & "<"
-        for i in 1 .. origTyp.len-2:
+        for i in 1..<origTyp.len-1:
           if i > 1: result.add(" COMMA ")
-          addResultType(origTyp.sons[i])
+          addResultType(origTyp[i])
         result.add("> ")
       # always call for sideeffects:
       assert t.kind != tyTuple
@@ -861,7 +861,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
       # with the C macros for defining procs such as N_NIMCALL. We must
       # create a typedef for the type and use it in the proc signature:
       let typedefName = ~"TY" & $sig
-      addf(m.s[cfsTypes], "typedef $1 $2;$n", [result, typedefName])
+      m.s[cfsTypes].addf("typedef $1 $2;$n", [result, typedefName])
       m.typeCache[sig] = typedefName
       result = typedefName
     else:
@@ -877,7 +877,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
         let recdesc = if t.kind != tyTuple: getRecordDesc(m, t, result, check)
                       else: getTupleDesc(m, t, result, check)
         if not isImportedType(t):
-          add(m.s[cfsTypes], recdesc)
+          m.s[cfsTypes].add(recdesc)
         elif tfIncompleteStruct notin t.flags: addAbiCheck(m, t, result)
   of tySet:
     result = $t.kind & '_' & getTypeName(m, t.lastSon, hashType t.lastSon)
@@ -885,8 +885,8 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
     if not isImportedType(t):
       let s = int(getSize(m.config, t))
       case s
-      of 1, 2, 4, 8: addf(m.s[cfsTypes], "typedef NU$2 $1;$n", [result, rope(s*8)])
-      else: addf(m.s[cfsTypes], "typedef NU8 $1[$2];$n",
+      of 1, 2, 4, 8: m.s[cfsTypes].addf("typedef NU$2 $1;$n", [result, rope(s*8)])
+      else: m.s[cfsTypes].addf("typedef NU8 $1[$2];$n",
              [result, rope(getSize(m.config, t))])
   of tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tySink, tyOwned,
      tyUserTypeClass, tyUserTypeClassInst, tyInferred:
@@ -915,10 +915,10 @@ proc getClosureType(m: BModule, t: PType, kind: TClosureTypeKind): Rope =
   genProcParams(m, t, rettype, desc, check, declareEnvironment=kind != clHalf)
   if not isImportedType(t):
     if t.callConv != ccClosure or kind != clFull:
-      addf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n",
+      m.s[cfsTypes].addf("typedef $1_PTR($2, $3) $4;$n",
            [rope(CallingConvToStr[t.callConv]), rettype, result, desc])
     else:
-      addf(m.s[cfsTypes], "typedef struct {$n" &
+      m.s[cfsTypes].addf("typedef struct {$n" &
           "N_NIMCALL_PTR($2, ClP_0) $3;$n" &
           "void* ClE_0;$n} $1;$n",
            [result, rettype, desc])
@@ -926,7 +926,7 @@ proc getClosureType(m: BModule, t: PType, kind: TClosureTypeKind): Rope =
 proc finishTypeDescriptions(m: BModule) =
   var i = 0
   var check = initIntSet()
-  while i < len(m.typeStack):
+  while i < m.typeStack.len:
     let t = m.typeStack[i]
     if optSeqDestructors in m.config.globalOptions and t.skipTypes(abstractInst).kind == tySequence:
       seqV2ContentType(m, t, check)
@@ -964,11 +964,11 @@ proc genProcHeader(m: BModule, prc: PSym, asPtr: bool = false): Rope =
   let asPtrStr = rope(if asPtr: "_PTR" else: "")
   var name = prc.loc.r
   if isReloadable(m, prc) and not asPtr:
-    add(name, "_actual")
+    name.add("_actual")
   # careful here! don't access ``prc.ast`` as that could reload large parts of
   # the object graph!
   if prc.constraint.isNil:
-    addf(result, "$1$2($3, $4)$5",
+    result.addf("$1$2($3, $4)$5",
          [rope(CallingConvToStr[prc.typ.callConv]), asPtrStr, rettype, name,
          params])
   else:
@@ -999,7 +999,7 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType;
   var size: Rope
   if tfIncompleteStruct in typ.flags: size = rope"void*"
   else: size = getTypeDesc(m, origType)
-  addf(m.s[cfsTypeInit3],
+  m.s[cfsTypeInit3].addf(
        "$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n",
        [nameHcr, size, rope(nimtypeKind), base])
   # compute type flags for GC optimization
@@ -1008,30 +1008,30 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType;
   if not canFormAcycle(typ): flags = flags or 2
   #else MessageOut("can contain a cycle: " & typeToString(typ))
   if flags != 0:
-    addf(m.s[cfsTypeInit3], "$1.flags = $2;$n", [nameHcr, rope(flags)])
+    m.s[cfsTypeInit3].addf("$1.flags = $2;$n", [nameHcr, rope(flags)])
   discard cgsym(m, "TNimType")
   if isDefined(m.config, "nimTypeNames"):
     var typename = typeToString(if origType.typeInst != nil: origType.typeInst
                                 else: origType, preferName)
     if typename == "ref object" and origType.skipTypes(skipPtrs).sym != nil:
       typename = "anon ref object from " & m.config$origType.skipTypes(skipPtrs).sym.info
-    addf(m.s[cfsTypeInit3], "$1.name = $2;$n",
+    m.s[cfsTypeInit3].addf("$1.name = $2;$n",
         [nameHcr, makeCString typename])
     discard cgsym(m, "nimTypeRoot")
-    addf(m.s[cfsTypeInit3], "$1.nextType = nimTypeRoot; nimTypeRoot=&$1;$n",
+    m.s[cfsTypeInit3].addf("$1.nextType = nimTypeRoot; nimTypeRoot=&$1;$n",
          [nameHcr])
 
   if m.hcrOn:
-    addf(m.s[cfsVars], "static TNimType* $1;$n", [name])
-    addf(m.hcrCreateTypeInfosProc, "\thcrRegisterGlobal($2, \"$1\", sizeof(TNimType), NULL, (void**)&$1);$n",
+    m.s[cfsVars].addf("static TNimType* $1;$n", [name])
+    m.hcrCreateTypeInfosProc.addf("\thcrRegisterGlobal($2, \"$1\", sizeof(TNimType), NULL, (void**)&$1);$n",
          [name, getModuleDllPath(m, m.module)])
   else:
-    addf(m.s[cfsVars], "TNimType $1;$n", [name])
+    m.s[cfsVars].addf("TNimType $1;$n", [name])
 
 proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope;
                     info: TLineInfo) =
   var base: Rope
-  if len(typ) > 0 and typ.lastSon != nil:
+  if typ.len > 0 and typ.lastSon != nil:
     var x = typ.lastSon
     if typ.kind == tyObject: x = x.skipTypes(skipPtrs)
     if typ.kind == tyPtr and x.kind == tyObject and incompleteType(x):
@@ -1046,7 +1046,7 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope =
   # bugfix: we need to search the type that contains the discriminator:
   var objtype = objtype.skipTypes(abstractPtrs)
   while lookupInRecord(objtype.n, d.name) == nil:
-    objtype = objtype.sons[0].skipTypes(abstractPtrs)
+    objtype = objtype[0].skipTypes(abstractPtrs)
   if objtype.sym == nil:
     internalError(m.config, d.info, "anonymous obj with discriminator")
   result = "NimDT_$1_$2" % [rope($hashType(objtype)), rope(d.name.s.mangle)]
@@ -1060,67 +1060,66 @@ proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope =
 
 proc genTNimNodeArray(m: BModule, name: Rope, size: Rope) =
   if m.hcrOn:
-    addf(m.s[cfsVars], "static TNimNode** $1;$n", [name])
-    addf(m.hcrCreateTypeInfosProc, "\thcrRegisterGlobal($3, \"$1\", sizeof(TNimNode*) * $2, NULL, (void**)&$1);$n",
+    m.s[cfsVars].addf("static TNimNode** $1;$n", [name])
+    m.hcrCreateTypeInfosProc.addf("\thcrRegisterGlobal($3, \"$1\", sizeof(TNimNode*) * $2, NULL, (void**)&$1);$n",
          [name, size, getModuleDllPath(m, m.module)])
   else:
-    addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [name, size])
+    m.s[cfsTypeInit1].addf("static TNimNode* $1[$2];$n", [name, size])
 
 proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
                      info: TLineInfo) =
   case n.kind
   of nkRecList:
-    var L = len(n)
-    if L == 1:
-      genObjectFields(m, typ, origType, n.sons[0], expr, info)
-    elif L > 0:
-      var tmp = getTempName(m) & "_" & $L
-      genTNimNodeArray(m, tmp, rope(L))
-      for i in 0 ..< L:
+    if n.len == 1:
+      genObjectFields(m, typ, origType, n[0], expr, info)
+    elif n.len > 0:
+      var tmp = getTempName(m) & "_" & $n.len
+      genTNimNodeArray(m, tmp, rope(n.len))
+      for i in 0..<n.len:
         var tmp2 = getNimNode(m)
-        addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(i), tmp2])
-        genObjectFields(m, typ, origType, n.sons[i], tmp2, info)
-      addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
-           [expr, rope(L), tmp])
+        m.s[cfsTypeInit3].addf("$1[$2] = &$3;$n", [tmp, rope(i), tmp2])
+        genObjectFields(m, typ, origType, n[i], tmp2, info)
+      m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
+           [expr, rope(n.len), tmp])
     else:
-      addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n", [expr, rope(L)])
+      m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 2;$n", [expr, rope(n.len)])
   of nkRecCase:
-    assert(n.sons[0].kind == nkSym)
-    var field = n.sons[0].sym
+    assert(n[0].kind == nkSym)
+    var field = n[0].sym
     var tmp = discriminatorTableName(m, typ, field)
     var L = lengthOrd(m.config, field.typ)
     assert L > 0
     if field.loc.r == nil: fillObjectFields(m, typ)
     if field.loc.t == nil:
       internalError(m.config, n.info, "genObjectFields")
-    addf(m.s[cfsTypeInit3], "$1.kind = 3;$n" &
+    m.s[cfsTypeInit3].addf("$1.kind = 3;$n" &
         "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
         "$1.name = $5;$n" & "$1.sons = &$6[0];$n" &
         "$1.len = $7;$n", [expr, getTypeDesc(m, origType), field.loc.r,
                            genTypeInfo(m, field.typ, info),
                            makeCString(field.name.s),
                            tmp, rope(L)])
-    addf(m.s[cfsData], "TNimNode* $1[$2];$n", [tmp, rope(L+1)])
-    for i in 1 ..< len(n):
-      var b = n.sons[i]           # branch
+    m.s[cfsData].addf("TNimNode* $1[$2];$n", [tmp, rope(L+1)])
+    for i in 1..<n.len:
+      var b = n[i]           # branch
       var tmp2 = getNimNode(m)
       genObjectFields(m, typ, origType, lastSon(b), tmp2, info)
       case b.kind
       of nkOfBranch:
-        if len(b) < 2:
+        if b.len < 2:
           internalError(m.config, b.info, "genObjectFields; nkOfBranch broken")
-        for j in 0 .. len(b) - 2:
-          if b.sons[j].kind == nkRange:
-            var x = toInt(getOrdValue(b.sons[j].sons[0]))
-            var y = toInt(getOrdValue(b.sons[j].sons[1]))
+        for j in 0..<b.len - 1:
+          if b[j].kind == nkRange:
+            var x = toInt(getOrdValue(b[j][0]))
+            var y = toInt(getOrdValue(b[j][1]))
             while x <= y:
-              addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(x), tmp2])
+              m.s[cfsTypeInit3].addf("$1[$2] = &$3;$n", [tmp, rope(x), tmp2])
               inc(x)
           else:
-            addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
-                 [tmp, rope(getOrdValue(b.sons[j])), tmp2])
+            m.s[cfsTypeInit3].addf("$1[$2] = &$3;$n",
+                 [tmp, rope(getOrdValue(b[j])), tmp2])
       of nkElse:
-        addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
+        m.s[cfsTypeInit3].addf("$1[$2] = &$3;$n",
              [tmp, rope(L), tmp2])
       else: internalError(m.config, n.info, "genObjectFields(nkRecCase)")
   of nkSym:
@@ -1131,7 +1130,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
       if field.loc.r == nil: fillObjectFields(m, typ)
       if field.loc.t == nil:
         internalError(m.config, n.info, "genObjectFields")
-      addf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
+      m.s[cfsTypeInit3].addf("$1.kind = 1;$n" &
           "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
           "$1.name = $5;$n", [expr, getTypeDesc(m, origType),
           field.loc.r, genTypeInfo(m, field.typ, info), makeCString(field.name.s)])
@@ -1148,35 +1147,34 @@ proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo
   var tmp = getNimNode(m)
   if not isImportedType(typ):
     genObjectFields(m, typ, origType, typ.n, tmp, info)
-  addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [tiNameForHcr(m, name), tmp])
-  var t = typ.sons[0]
+  m.s[cfsTypeInit3].addf("$1.node = &$2;$n", [tiNameForHcr(m, name), tmp])
+  var t = typ[0]
   while t != nil:
     t = t.skipTypes(skipPtrs)
     t.flags.incl tfObjHasKids
-    t = t.sons[0]
+    t = t[0]
 
 proc genTupleInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo) =
   genTypeInfoAuxBase(m, typ, typ, name, rope("0"), info)
   var expr = getNimNode(m)
-  var length = len(typ)
-  if length > 0:
-    var tmp = getTempName(m) & "_" & $length
-    genTNimNodeArray(m, tmp, rope(length))
-    for i in 0 ..< length:
-      var a = typ.sons[i]
+  if typ.len > 0:
+    var tmp = getTempName(m) & "_" & $typ.len
+    genTNimNodeArray(m, tmp, rope(typ.len))
+    for i in 0..<typ.len:
+      var a = typ[i]
       var tmp2 = getNimNode(m)
-      addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(i), tmp2])
-      addf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
+      m.s[cfsTypeInit3].addf("$1[$2] = &$3;$n", [tmp, rope(i), tmp2])
+      m.s[cfsTypeInit3].addf("$1.kind = 1;$n" &
           "$1.offset = offsetof($2, Field$3);$n" &
           "$1.typ = $4;$n" &
           "$1.name = \"Field$3\";$n",
            [tmp2, getTypeDesc(m, origType), rope(i), genTypeInfo(m, a, info)])
-    addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
-         [expr, rope(length), tmp])
+    m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
+         [expr, rope(typ.len), tmp])
   else:
-    addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n",
-         [expr, rope(length)])
-  addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [tiNameForHcr(m, name), expr])
+    m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 2;$n",
+         [expr, rope(typ.len)])
+  m.s[cfsTypeInit3].addf("$1.node = &$2;$n", [tiNameForHcr(m, name), expr])
 
 proc genEnumInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
   # Type information for enumerations is quite heavy, so we do some
@@ -1184,51 +1182,50 @@ proc genEnumInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
   # anyway. We generate a cstring array and a loop over it. Exceptional
   # positions will be reset after the loop.
   genTypeInfoAux(m, typ, typ, name, info)
-  var length = len(typ.n)
-  var nodePtrs = getTempName(m) & "_" & $length
-  genTNimNodeArray(m, nodePtrs, rope(length))
+  var nodePtrs = getTempName(m) & "_" & $typ.n.len
+  genTNimNodeArray(m, nodePtrs, rope(typ.n.len))
   var enumNames, specialCases: Rope
   var firstNimNode = m.typeNodes
   var hasHoles = false
-  for i in 0 ..< length:
-    assert(typ.n.sons[i].kind == nkSym)
-    var field = typ.n.sons[i].sym
+  for i in 0..<typ.n.len:
+    assert(typ.n[i].kind == nkSym)
+    var field = typ.n[i].sym
     var elemNode = getNimNode(m)
     if field.ast == nil:
       # no explicit string literal for the enum field, so use field.name:
-      add(enumNames, makeCString(field.name.s))
+      enumNames.add(makeCString(field.name.s))
     else:
-      add(enumNames, makeCString(field.ast.strVal))
-    if i < length - 1: add(enumNames, ", \L")
+      enumNames.add(makeCString(field.ast.strVal))
+    if i < typ.n.len - 1: enumNames.add(", \L")
     if field.position != i or tfEnumHasHoles in typ.flags:
-      addf(specialCases, "$1.offset = $2;$n", [elemNode, rope(field.position)])
+      specialCases.addf("$1.offset = $2;$n", [elemNode, rope(field.position)])
       hasHoles = true
   var enumArray = getTempName(m)
   var counter = getTempName(m)
-  addf(m.s[cfsTypeInit1], "NI $1;$n", [counter])
-  addf(m.s[cfsTypeInit1], "static char* NIM_CONST $1[$2] = {$n$3};$n",
-       [enumArray, rope(length), enumNames])
-  addf(m.s[cfsTypeInit3], "for ($1 = 0; $1 < $2; $1++) {$n" &
+  m.s[cfsTypeInit1].addf("NI $1;$n", [counter])
+  m.s[cfsTypeInit1].addf("static char* NIM_CONST $1[$2] = {$n$3};$n",
+       [enumArray, rope(typ.n.len), enumNames])
+  m.s[cfsTypeInit3].addf("for ($1 = 0; $1 < $2; $1++) {$n" &
       "$3[$1+$4].kind = 1;$n" & "$3[$1+$4].offset = $1;$n" &
       "$3[$1+$4].name = $5[$1];$n" & "$6[$1] = &$3[$1+$4];$n" & "}$n", [counter,
-      rope(length), m.typeNodesName, rope(firstNimNode), enumArray, nodePtrs])
-  add(m.s[cfsTypeInit3], specialCases)
-  addf(m.s[cfsTypeInit3],
+      rope(typ.n.len), m.typeNodesName, rope(firstNimNode), enumArray, nodePtrs])
+  m.s[cfsTypeInit3].add(specialCases)
+  m.s[cfsTypeInit3].addf(
        "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n$4.node = &$1;$n",
-       [getNimNode(m), rope(length), nodePtrs, tiNameForHcr(m, name)])
+       [getNimNode(m), rope(typ.n.len), nodePtrs, tiNameForHcr(m, name)])
   if hasHoles:
     # 1 << 2 is {ntfEnumHole}
-    addf(m.s[cfsTypeInit3], "$1.flags = 1<<2;$n", [tiNameForHcr(m, name)])
+    m.s[cfsTypeInit3].addf("$1.flags = 1<<2;$n", [tiNameForHcr(m, name)])
 
 proc genSetInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
-  assert(typ.sons[0] != nil)
+  assert(typ[0] != nil)
   genTypeInfoAux(m, typ, typ, name, info)
   var tmp = getNimNode(m)
-  addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n",
+  m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n",
        [tmp, rope(firstOrd(m.config, typ)), tiNameForHcr(m, name)])
 
 proc genArrayInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
-  genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1], info), info)
+  genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ[1], info), info)
 
 proc fakeClosureType(m: BModule; owner: PSym): PType =
   # we generate the same RTTI as for a tuple[pointer, ref tuple[]]
@@ -1243,16 +1240,16 @@ include ccgtrav
 
 proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
   genProc(m, s)
-  addf(m.s[cfsTypeInit3], "$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
+  m.s[cfsTypeInit3].addf("$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
      [result, s.loc.r])
 
 proc declareNimType(m: BModule, str: Rope, ownerModule: PSym) =
   if m.hcrOn:
-    addf(m.s[cfsVars], "static TNimType* $1;$n", [str])
-    addf(m.s[cfsTypeInit1], "\t$1 = (TNimType*)hcrGetGlobal($2, \"$1\");$n",
+    m.s[cfsVars].addf("static TNimType* $1;$n", [str])
+    m.s[cfsTypeInit1].addf("\t$1 = (TNimType*)hcrGetGlobal($2, \"$1\");$n",
           [str, getModuleDllPath(m, ownerModule)])
   else:
-    addf(m.s[cfsVars], "extern TNimType $1;$n", [str])
+    m.s[cfsVars].addf("extern TNimType $1;$n", [str])
 
 proc genTypeInfo2Name(m: BModule; t: PType): Rope =
   var res = "|"
@@ -1274,7 +1271,7 @@ proc genTypeInfo2Name(m: BModule; t: PType): Rope =
     else:
       res.add $hashType(it)
     res.add "|"
-    it = it.sons[0]
+    it = it[0]
   result = makeCString(res)
 
 proc trivialDestructor(s: PSym): bool {.inline.} = s.ast[bodyPos].len == 0
@@ -1298,8 +1295,8 @@ proc genObjectInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo
     d = t.destructor.loc.r
   else:
     d = rope("NIM_NIL")
-  addf(m.s[cfsVars], "TNimType $1;$n", [name])
-  addf(m.s[cfsTypeInit3], "$1.destructor = (void*)$2; $1.size = sizeof($3); $1.name = $4;$n", [
+  m.s[cfsVars].addf("TNimType $1;$n", [name])
+  m.s[cfsTypeInit3].addf("$1.destructor = (void*)$2; $1.size = sizeof($3); $1.name = $4;$n", [
     name, d, getTypeDesc(m, t), genTypeInfo2Name(m, t)])
 
 proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
@@ -1358,12 +1355,12 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
     if optSeqDestructors notin m.config.globalOptions:
       if m.config.selectedGC >= gcMarkAndSweep:
         let markerProc = genTraverseProc(m, origType, sig)
-        addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc])
+        m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc])
   of tyRef:
     genTypeInfoAux(m, t, t, result, info)
     if m.config.selectedGC >= gcMarkAndSweep:
       let markerProc = genTraverseProc(m, origType, sig)
-      addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc])
+      m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc])
   of tyPtr, tyRange, tyUncheckedArray: genTypeInfoAux(m, t, t, result, info)
   of tyArray: genArrayInfo(m, t, result, info)
   of tySet: genSetInfo(m, t, result, info)
diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim
index 3c7b0510e..f2a8c1e36 100644
--- a/compiler/ccgutils.nim
+++ b/compiler/ccgutils.nim
@@ -16,11 +16,11 @@ import
 proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
   case n.kind
   of nkStmtList:
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       result = getPragmaStmt(n[i], w)
       if result != nil: break
   of nkPragma:
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       if whichPragma(n[i]) == w: return n[i]
   else: discard
 
@@ -33,7 +33,7 @@ proc hashString*(conf: ConfigRef; s: string): BiggestInt =
     # we have to use the same bitwidth
     # as the target CPU
     var b = 0'u64
-    for i in 0 ..< len(s):
+    for i in 0..<s.len:
       b = b + uint(s[i])
       b = b + (b shl 10)
       b = b xor (b shr 6)
@@ -43,7 +43,7 @@ proc hashString*(conf: ConfigRef; s: string): BiggestInt =
     result = cast[Hash](b)
   else:
     var a = 0'u32
-    for i in 0 ..< len(s):
+    for i in 0..<s.len:
       a = a + uint32(s[i])
       a = a + (a shl 10)
       a = a xor (a shr 6)
@@ -70,18 +70,18 @@ proc mangle*(name: string): string =
   template special(x) =
     result.add x
     requiresUnderscore = true
-  for i in start..(name.len-1):
+  for i in start..<name.len:
     let c = name[i]
     case c
     of 'a'..'z', '0'..'9', 'A'..'Z':
-      add(result, c)
+      result.add(c)
     of '_':
       # we generate names like 'foo_9' for scope disambiguations and so
       # disallow this here:
       if i > 0 and i < name.len-1 and name[i+1] in Digits:
         discard
       else:
-        add(result, c)
+        result.add(c)
     of '$': special "dollar"
     of '%': special "percent"
     of '&': special "amp"
@@ -102,7 +102,7 @@ proc mangle*(name: string): string =
     of '@': special "at"
     of '|': special "bar"
     else:
-      add(result, "X" & toHex(ord(c), 2))
+      result.add("X" & toHex(ord(c), 2))
       requiresUnderscore = true
   if requiresUnderscore:
     result.add "_"
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index cfd1aeb24..831363805 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -38,7 +38,7 @@ when not declared(dynlib.libCandidates):
       for middle in split(substr(s, le + 1, ri - 1), '|'):
         libCandidates(prefix & middle & suffix, dest)
     else:
-      add(dest, s)
+      dest.add(s)
 
 when options.hasTinyCBackend:
   import tccgen
@@ -122,7 +122,6 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
   args.expectKind nnkBracket
   # echo "ropecg ", newLit(frmt).repr, ", ", args.repr
   var i = 0
-  var length = len(frmt)
   result = nnkStmtListExpr.newTree()
 
   result.add quote do:
@@ -142,7 +141,7 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
       result.add newCall(ident "add", resVar, newLit(strLit))
       strLit.setLen 0
 
-  while i < length:
+  while i < frmt.len:
     if frmt[i] == '$':
       inc(i)                  # skip '$'
       case frmt[i]
@@ -159,9 +158,9 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
         while true:
           j = (j * 10) + ord(frmt[i]) - ord('0')
           inc(i)
-          if i >= length or not (frmt[i] in {'0'..'9'}): break
+          if i >= frmt.len or not (frmt[i] in {'0'..'9'}): break
         num = j
-        if j > len(args):
+        if j > args.len:
           error("ropes: invalid format string " & newLit(frmt).repr & " args.len: " & $args.len)
 
         flushStrLit()
@@ -170,7 +169,7 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
         flushStrLit()
         result.add quote do:
           if optLineDir notin `m`.config.options:
-            add(`resVar`, "\L")
+            `resVar`.add("\L")
         inc(i)
       of 'N':
         strLit.add "\L"
@@ -195,49 +194,49 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
       flushStrLit()
       result.add newCall(formatValue, resVar, newCall(ident"cgsym", m, ident))
     var start = i
-    while i < length:
+    while i < frmt.len:
       if frmt[i] != '$' and frmt[i] != '#': inc(i)
       else: break
     if i - 1 >= start:
-      add(strLit, substr(frmt, start, i - 1))
+      strLit.add(substr(frmt, start, i - 1))
 
   flushStrLit()
   result.add newCall(ident"rope", resVar)
 
 proc indentLine(p: BProc, r: Rope): Rope =
   result = r
-  for i in 0 ..< p.blocks.len:
+  for i in 0..<p.blocks.len:
     prepend(result, "\t".rope)
 
 template appcg(m: BModule, c: var Rope, frmt: FormatStr,
            args: untyped) =
-  add(c, ropecg(m, frmt, args))
+  c.add(ropecg(m, frmt, args))
 
 template appcg(m: BModule, sec: TCFileSection, frmt: FormatStr,
            args: untyped) =
-  add(m.s[sec], ropecg(m, frmt, args))
+  m.s[sec].add(ropecg(m, frmt, args))
 
 template appcg(p: BProc, sec: TCProcSection, frmt: FormatStr,
            args: untyped) =
-  add(p.s(sec), ropecg(p.module, frmt, args))
+  p.s(sec).add(ropecg(p.module, frmt, args))
 
 template line(p: BProc, sec: TCProcSection, r: Rope) =
-  add(p.s(sec), indentLine(p, r))
+  p.s(sec).add(indentLine(p, r))
 
 template line(p: BProc, sec: TCProcSection, r: string) =
-  add(p.s(sec), indentLine(p, r.rope))
+  p.s(sec).add(indentLine(p, r.rope))
 
 template lineF(p: BProc, sec: TCProcSection, frmt: FormatStr,
               args: untyped) =
-  add(p.s(sec), indentLine(p, frmt % args))
+  p.s(sec).add(indentLine(p, frmt % args))
 
 template lineCg(p: BProc, sec: TCProcSection, frmt: FormatStr,
                args: untyped) =
-  add(p.s(sec), indentLine(p, ropecg(p.module, frmt, args)))
+  p.s(sec).add(indentLine(p, ropecg(p.module, frmt, args)))
 
 template linefmt(p: BProc, sec: TCProcSection, frmt: FormatStr,
              args: untyped) =
-  add(p.s(sec), indentLine(p, ropecg(p.module, frmt, args)))
+  p.s(sec).add(indentLine(p, ropecg(p.module, frmt, args)))
 
 proc safeLineNm(info: TLineInfo): int =
   result = toLinenumber(info)
@@ -246,7 +245,7 @@ proc safeLineNm(info: TLineInfo): int =
 proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) =
   assert line >= 0
   if optLineDir in conf.options:
-    addf(r, "$N#line $2 $1$N",
+    r.addf("$N#line $2 $1$N",
         [rope(makeSingleLineCString(filename)), rope(line)])
 
 proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) =
@@ -263,7 +262,7 @@ proc genLineDir(p: BProc, t: PNode) =
   let line = t.info.safeLineNm
 
   if optEmbedOrigSrc in p.config.globalOptions:
-    add(p.s(cpsStmts), ~"//" & sourceLine(p.config, t.info) & "\L")
+    p.s(cpsStmts).add(~"//" & sourceLine(p.config, t.info) & "\L")
   genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p.config)
   if ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and
       (p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx:
@@ -272,7 +271,7 @@ proc genLineDir(p: BProc, t: PNode) =
               [line, quotedFilename(p.config, t.info)])
 
 proc postStmtActions(p: BProc) {.inline.} =
-  add(p.s(cpsStmts), p.module.injectStmt)
+  p.s(cpsStmts).add(p.module.injectStmt)
 
 proc accessThreadLocalVar(p: BProc, s: PSym)
 proc emulatedThreadVars(conf: ConfigRef): bool {.inline.}
@@ -343,9 +342,9 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
     if not takeAddr: r = "(*$1)" % [r]
     var s = skipTypes(t, abstractInst)
     if not p.module.compileToCpp:
-      while s.kind == tyObject and s.sons[0] != nil:
-        add(r, ".Sup")
-        s = skipTypes(s.sons[0], skipPtrs)
+      while s.kind == tyObject and s[0] != nil:
+        r.add(".Sup")
+        s = skipTypes(s[0], skipPtrs)
     linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfo(p.module, t, a.lode.info)])
   of frEmbedded:
     if optTinyRtti in p.config.globalOptions:
@@ -360,9 +359,9 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
     if not takeAddr: r = "(*$1)" % [r]
     var s = skipTypes(t, abstractInst)
     if not p.module.compileToCpp:
-      while s.kind == tyObject and s.sons[0] != nil and s.sym.magic != mException:
-        add(r, ".Sup")
-        s = skipTypes(s.sons[0], skipPtrs)
+      while s.kind == tyObject and s[0] != nil and s.sym.magic != mException:
+        r.add(".Sup")
+        s = skipTypes(s[0], skipPtrs)
     linefmt(p, section, "$1.name = $2;$n", [r, makeCString(t.skipTypes(abstractInst).sym.name.s)])
 
 type
@@ -483,12 +482,12 @@ proc localVarDecl(p: BProc; n: PNode): Rope =
     result.addf("NIM_ALIGN($1) ", [rope(s.alignment)])
   result.add getTypeDesc(p.module, s.typ)
   if s.constraint.isNil:
-    if sfRegister in s.flags: add(result, " register")
+    if sfRegister in s.flags: result.add(" register")
     #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
-    #  add(decl, " GC_GUARD")
-    if sfVolatile in s.flags: add(result, " volatile")
-    add(result, " ")
-    add(result, s.loc.r)
+    #  decl.add(" GC_GUARD")
+    if sfVolatile in s.flags: result.add(" volatile")
+    result.add(" ")
+    result.add(s.loc.r)
   else:
     result = runtimeFormat(s.cgDeclFrmt, [result, s.loc.r])
 
@@ -534,16 +533,16 @@ proc assignGlobalVar(p: BProc, n: PNode) =
       if s.constraint.isNil:
         if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
           decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)]
-        if p.hcrOn: add(decl, "static ")
-        elif sfImportc in s.flags: add(decl, "extern ")
-        add(decl, td)
-        if p.hcrOn: add(decl, "*")
-        if sfRegister in s.flags: add(decl, " register")
-        if sfVolatile in s.flags: add(decl, " volatile")
-        addf(decl, " $1;$n", [s.loc.r])
+        if p.hcrOn: decl.add("static ")
+        elif sfImportc in s.flags: decl.add("extern ")
+        decl.add(td)
+        if p.hcrOn: decl.add("*")
+        if sfRegister in s.flags: decl.add(" register")
+        if sfVolatile in s.flags: decl.add(" volatile")
+        decl.addf(" $1;$n", [s.loc.r])
       else:
         decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r])
-      add(p.module.s[cfsVars], decl)
+      p.module.s[cfsVars].add(decl)
   if p.withinLoop > 0:
     # fixes tests/run/tzeroarray:
     resetLoc(p, s.loc)
@@ -621,7 +620,7 @@ proc initFrame(p: BProc, procname, filename: Rope): Rope =
 
 proc initFrameNoDebug(p: BProc; frame, procname, filename: Rope; line: int): Rope =
   discard cgsym(p.module, "nimFrame")
-  addf(p.blocks[0].sections[cpsLocals], "TFrame $1;$n", [frame])
+  p.blocks[0].sections[cpsLocals].addf("TFrame $1;$n", [frame])
   result = ropecg(p.module, "\t$1.procname = $2; $1.filename = $3; " &
                       " $1.line = $4; $1.len = -1; nimFrame(&$1);$n",
                       [frame, procname, filename, line])
@@ -649,15 +648,15 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
     var tmp = getTempName(m)
     assert(lib.name == nil)
     lib.name = tmp # BUGFIX: cgsym has awful side-effects
-    addf(m.s[cfsVars], "static void* $1;$n", [tmp])
+    m.s[cfsVars].addf("static void* $1;$n", [tmp])
     if lib.path.kind in {nkStrLit..nkTripleStrLit}:
       var s: TStringSeq = @[]
       libCandidates(lib.path.strVal, s)
       rawMessage(m.config, hintDependency, lib.path.strVal)
       var loadlib: Rope = nil
-      for i in 0 .. high(s):
+      for i in 0..high(s):
         inc(m.labels)
-        if i > 0: add(loadlib, "||")
+        if i > 0: loadlib.add("||")
         let n = newStrNode(nkStrLit, s[i])
         n.info = lib.path.info
         appcg(m, loadlib, "($1 = #nimLoadLibrary($2))$n",
@@ -675,9 +674,9 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
            [getTypeDesc(m, lib.path.typ), rdLoc(dest)])
       expr(p, lib.path, dest)
 
-      add(m.s[cfsVars], p.s(cpsLocals))
-      add(m.s[cfsDynLibInit], p.s(cpsInit))
-      add(m.s[cfsDynLibInit], p.s(cpsStmts))
+      m.s[cfsVars].add(p.s(cpsLocals))
+      m.s[cfsDynLibInit].add(p.s(cpsInit))
+      m.s[cfsDynLibInit].add(p.s(cpsStmts))
       appcg(m, m.s[cfsDynLibInit],
            "if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n",
            [tmp, rdLoc(dest)])
@@ -707,27 +706,27 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
     var a: TLoc
     initLocExpr(m.initProc, n[0], a)
     var params = rdLoc(a) & "("
-    for i in 1 .. n.len-2:
+    for i in 1..<n.len-1:
       initLocExpr(m.initProc, n[i], a)
       params.add(rdLoc(a))
       params.add(", ")
     let load = "\t$1 = ($2) ($3$4));$n" %
         [tmp, getTypeDesc(m, sym.typ), params, makeCString($extname)]
     var last = lastSon(n)
-    if last.kind == nkHiddenStdConv: last = last.sons[1]
+    if last.kind == nkHiddenStdConv: last = last[1]
     internalAssert(m.config, last.kind == nkStrLit)
     let idx = last.strVal
     if idx.len == 0:
-      add(m.initProc.s(cpsStmts), load)
+      m.initProc.s(cpsStmts).add(load)
     elif idx.len == 1 and idx[0] in {'0'..'9'}:
-      add(m.extensionLoaders[idx[0]], load)
+      m.extensionLoaders[idx[0]].add(load)
     else:
       internalError(m.config, sym.info, "wrong index: " & idx)
   else:
     appcg(m, m.s[cfsDynLibInit],
         "\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
         [tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)])
-  addf(m.s[cfsVars], "$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)])
+  m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)])
 
 proc varInDynamicLib(m: BModule, sym: PSym) =
   var lib = sym.annex
@@ -740,7 +739,7 @@ proc varInDynamicLib(m: BModule, sym: PSym) =
   appcg(m, m.s[cfsDynLibInit],
       "$1 = ($2*) #nimGetProcAddr($3, $4);$n",
       [tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)])
-  addf(m.s[cfsVars], "$2* $1;$n",
+  m.s[cfsVars].addf("$2* $1;$n",
       [sym.loc.r, getTypeDesc(m, sym.loc.t)])
 
 proc symInDynamicLibPartial(m: BModule, sym: PSym) =
@@ -765,16 +764,16 @@ proc cgsym(m: BModule, name: string): Rope =
     result.addActualSuffixForHCR(m.module, sym)
 
 proc generateHeaders(m: BModule) =
-  add(m.s[cfsHeaders], "\L#include \"nimbase.h\"\L")
+  m.s[cfsHeaders].add("\L#include \"nimbase.h\"\L")
 
   for it in m.headerFiles:
     if it[0] == '#':
-      add(m.s[cfsHeaders], rope(it.replace('`', '"') & "\L"))
+      m.s[cfsHeaders].add(rope(it.replace('`', '"') & "\L"))
     elif it[0] notin {'"', '<'}:
-      addf(m.s[cfsHeaders], "#include \"$1\"$N", [rope(it)])
+      m.s[cfsHeaders].addf("#include \"$1\"$N", [rope(it)])
     else:
-      addf(m.s[cfsHeaders], "#include $1$N", [rope(it)])
-  add(m.s[cfsHeaders], """#undef LANGUAGE_C
+      m.s[cfsHeaders].addf("#include $1$N", [rope(it)])
+  m.s[cfsHeaders].add("""#undef LANGUAGE_C
 #undef MIPSEB
 #undef MIPSEL
 #undef PPC
@@ -942,7 +941,7 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
       else:
         allPathsInBranch(it.lastSon)
   else:
-    for i in 0..<safeLen(n):
+    for i in 0..<n.safeLen:
       allPathsInBranch(n[i])
 
 proc getProcTypeCast(m: BModule, prc: PSym): Rope =
@@ -963,12 +962,12 @@ proc genProcAux(m: BModule, prc: PSym) =
   if sfInjectDestructors in prc.flags:
     procBody = injectDestructorCalls(m.g.graph, prc, procBody)
 
-  if sfPure notin prc.flags and prc.typ.sons[0] != nil:
+  if sfPure notin prc.flags and prc.typ[0] != nil:
     if resultPos >= prc.ast.len:
       internalError(m.config, prc.info, "proc has no result symbol")
-    let resNode = prc.ast.sons[resultPos]
+    let resNode = prc.ast[resultPos]
     let res = resNode.sym # get result symbol
-    if not isInvalidReturnType(m.config, prc.typ.sons[0]):
+    if not isInvalidReturnType(m.config, prc.typ[0]):
       if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
       if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil):
         var decl = localVarDecl(p, resNode)
@@ -998,8 +997,8 @@ proc genProcAux(m: BModule, prc: PSym) =
         #incl(res.loc.flags, lfIndirect)
         res.loc.storage = OnUnknown
 
-  for i in 1 ..< len(prc.typ.n):
-    let param = prc.typ.n.sons[i].sym
+  for i in 1..<prc.typ.n.len:
+    let param = prc.typ.n[i].sym
     if param.typ.isCompileTimeOnly: continue
     assignParam(p, param, prc.typ[0])
   closureSetup(p, prc)
@@ -1019,29 +1018,29 @@ proc genProcAux(m: BModule, prc: PSym) =
       # Add forward declaration for "_actual"-suffixed functions defined in the same module (or inline).
       # This fixes the use of methods and also the case when 2 functions within the same module
       # call each other using directly the "_actual" versions (an optimization) - see issue #11608
-      addf(m.s[cfsProcHeaders], "$1;\n", [header])
+      m.s[cfsProcHeaders].addf("$1;\n", [header])
     generatedProc.add ropecg(p.module, "$1 {", [header])
-    add(generatedProc, initGCFrame(p))
+    generatedProc.add(initGCFrame(p))
     if optStackTrace in prc.options:
-      add(generatedProc, p.s(cpsLocals))
+      generatedProc.add(p.s(cpsLocals))
       var procname = makeCString(prc.name.s)
-      add(generatedProc, initFrame(p, procname, quotedFilename(p.config, prc.info)))
+      generatedProc.add(initFrame(p, procname, quotedFilename(p.config, prc.info)))
     else:
-      add(generatedProc, p.s(cpsLocals))
+      generatedProc.add(p.s(cpsLocals))
     if optProfiler in prc.options:
       # invoke at proc entry for recursion:
       appcg(p, cpsInit, "\t#nimProfile();$n", [])
-    if p.beforeRetNeeded: add(generatedProc, "{")
-    add(generatedProc, p.s(cpsInit))
-    add(generatedProc, p.s(cpsStmts))
-    if p.beforeRetNeeded: add(generatedProc, ~"\t}BeforeRet_: ;$n")
-    add(generatedProc, deinitGCFrame(p))
-    if optStackTrace in prc.options: add(generatedProc, deinitFrame(p))
-    add(generatedProc, returnStmt)
-    add(generatedProc, ~"}$N")
-  add(m.s[cfsProcs], generatedProc)
+    if p.beforeRetNeeded: generatedProc.add("{")
+    generatedProc.add(p.s(cpsInit))
+    generatedProc.add(p.s(cpsStmts))
+    if p.beforeRetNeeded: generatedProc.add(~"\t}BeforeRet_: ;$n")
+    generatedProc.add(deinitGCFrame(p))
+    if optStackTrace in prc.options: generatedProc.add(deinitFrame(p))
+    generatedProc.add(returnStmt)
+    generatedProc.add(~"}$N")
+  m.s[cfsProcs].add(generatedProc)
   if isReloadable(m, prc):
-    addf(m.s[cfsDynLibInit], "\t$1 = ($3) hcrRegisterProc($4, \"$1\", (void*)$2);$n",
+    m.s[cfsDynLibInit].addf("\t$1 = ($3) hcrRegisterProc($4, \"$1\", (void*)$2);$n",
          [prc.loc.r, prc.loc.r & "_actual", getProcTypeCast(m, prc), getModuleDllPath(m, prc)])
 
 proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} =
@@ -1059,11 +1058,11 @@ proc genProcPrototype(m: BModule, sym: PSym) =
   if lfDynamicLib in sym.loc.flags:
     if getModule(sym).id != m.module.id and
         not containsOrIncl(m.declaredThings, sym.id):
-      add(m.s[cfsVars], ropecg(m, "$1 $2 $3;$n",
+      m.s[cfsVars].add(ropecg(m, "$1 $2 $3;$n",
                         [(if isReloadable(m, sym): "static" else: "extern"),
                         getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)]))
       if isReloadable(m, sym):
-        addf(m.s[cfsDynLibInit], "\t$1 = ($2) hcrGetProc($3, \"$1\");$n",
+        m.s[cfsDynLibInit].addf("\t$1 = ($2) hcrGetProc($3, \"$1\");$n",
              [mangleDynLibProc(sym), getTypeDesc(m, sym.loc.t), getModuleDllPath(m, sym)])
   elif not containsOrIncl(m.declaredProtos, sym.id):
     let asPtr = isReloadable(m, sym)
@@ -1077,7 +1076,7 @@ proc genProcPrototype(m: BModule, sym: PSym) =
         header.add(" __attribute__((naked))")
       if sfNoReturn in sym.flags and hasAttribute in CC[m.config.cCompiler].props:
         header.add(" __attribute__((noreturn))")
-    add(m.s[cfsProcHeaders], ropecg(m, "$1;$N", [header]))
+    m.s[cfsProcHeaders].add(ropecg(m, "$1;$N", [header]))
 
 # TODO: figure out how to rename this - it DOES generate a forward declaration
 proc genProcNoForward(m: BModule, prc: PSym) =
@@ -1116,7 +1115,7 @@ proc genProcNoForward(m: BModule, prc: PSym) =
       # reloadable (and has no _actual suffix) - other modules will need to be able to get it through
       # the hcr dynlib (also put it in the DynLibInit section - right after it gets loaded)
       if isReloadable(q, prc):
-        addf(q.s[cfsDynLibInit], "\t$1 = ($2) hcrRegisterProc($3, \"$1\", (void*)$1);$n",
+        q.s[cfsDynLibInit].addf("\t$1 = ($2) hcrRegisterProc($3, \"$1\", (void*)$1);$n",
             [prc.loc.r, getTypeDesc(q, prc.loc.t), getModuleDllPath(m, q.module)])
     else:
       symInDynamicLibPartial(m, prc)
@@ -1128,7 +1127,7 @@ proc genProcNoForward(m: BModule, prc: PSym) =
     # to do the declaredProtos check before the call to genProcPrototype
     if isReloadable(m, prc) and prc.id notin m.declaredProtos and
       q != nil and q.module.id != m.module.id:
-      addf(m.s[cfsDynLibInit], "\t$1 = ($2) hcrGetProc($3, \"$1\");$n",
+      m.s[cfsDynLibInit].addf("\t$1 = ($2) hcrGetProc($3, \"$1\");$n",
            [prc.loc.r, getProcTypeCast(m, prc), getModuleDllPath(m, prc)])
     genProcPrototype(m, prc)
     if q != nil and not containsOrIncl(q.declaredThings, prc.id):
@@ -1152,16 +1151,16 @@ proc requestConstImpl(p: BProc, sym: PSym) =
   var q = findPendingModule(m, sym)
   if q != nil and not containsOrIncl(q.declaredThings, sym.id):
     assert q.initProc.module == q
-    addf(q.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
+    q.s[cfsData].addf("NIM_CONST $1 $2 = $3;$n",
         [getTypeDesc(q, sym.typ), sym.loc.r, genConstExpr(q.initProc, sym.ast)])
   # declare header:
   if q != m and not containsOrIncl(m.declaredThings, sym.id):
     assert(sym.loc.r != nil)
     let headerDecl = "extern NIM_CONST $1 $2;$n" %
         [getTypeDesc(m, sym.loc.t), sym.loc.r]
-    add(m.s[cfsData], headerDecl)
+    m.s[cfsData].add(headerDecl)
     if sfExportc in sym.flags and p.module.g.generatedHeader != nil:
-      add(p.module.g.generatedHeader.s[cfsData], headerDecl)
+      p.module.g.generatedHeader.s[cfsData].add(headerDecl)
 
 proc isActivated(prc: PSym): bool = prc.typ != nil
 
@@ -1197,19 +1196,19 @@ proc genVarPrototype(m: BModule, n: PNode) =
       incl(m.declaredThings, sym.id)
       if sym.kind in {skLet, skVar, skField, skForVar} and sym.alignment > 0:
         m.s[cfsVars].addf "NIM_ALIGN($1) ", [rope(sym.alignment)]
-      add(m.s[cfsVars], if m.hcrOn: "static " else: "extern ")
-      add(m.s[cfsVars], getTypeDesc(m, sym.loc.t))
-      if m.hcrOn: add(m.s[cfsVars], "*")
-      if lfDynamicLib in sym.loc.flags: add(m.s[cfsVars], "*")
-      if sfRegister in sym.flags: add(m.s[cfsVars], " register")
-      if sfVolatile in sym.flags: add(m.s[cfsVars], " volatile")
-      addf(m.s[cfsVars], " $1;$n", [sym.loc.r])
-      if m.hcrOn: addf(m.initProc.procSec(cpsLocals),
+      m.s[cfsVars].add(if m.hcrOn: "static " else: "extern ")
+      m.s[cfsVars].add(getTypeDesc(m, sym.loc.t))
+      if m.hcrOn: m.s[cfsVars].add("*")
+      if lfDynamicLib in sym.loc.flags: m.s[cfsVars].add("*")
+      if sfRegister in sym.flags: m.s[cfsVars].add(" register")
+      if sfVolatile in sym.flags: m.s[cfsVars].add(" volatile")
+      m.s[cfsVars].addf(" $1;$n", [sym.loc.r])
+      if m.hcrOn: m.initProc.procSec(cpsLocals).addf(
         "\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r,
         getTypeDesc(m, sym.loc.t), getModuleDllPath(m, sym)])
 
 proc addIntTypes(result: var Rope; conf: ConfigRef) {.inline.} =
-  addf(result, "#define NIM_INTBITS $1\L", [
+  result.addf("#define NIM_INTBITS $1\L", [
     platform.CPU[conf.target.targetCPU].intSize.rope])
   if conf.cppCustomNamespace.len > 0:
     result.add("#define USE_NIM_NAMESPACE ")
@@ -1236,7 +1235,7 @@ proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope =
 
 proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope =
   result = getCopyright(conf, cfile)
-  if conf.hcrOn: add(result, "#define NIM_HOT_CODE_RELOADING\L")
+  if conf.hcrOn: result.add("#define NIM_HOT_CODE_RELOADING\L")
   addIntTypes(result, conf)
 
 proc getSomeNameForModule(m: PSym): Rope =
@@ -1280,15 +1279,15 @@ proc genMainProc(m: BModule) =
                        "\t\t#nimLoadLibraryError($2);$N",
                        [handle, genStringLiteral(m, n)])
 
-    add(preMainCode, loadLib("hcr_handle", "hcrGetProc"))
-    add(preMainCode, "\tvoid* rtl_handle;\L")
-    add(preMainCode, loadLib("rtl_handle", "nimGC_setStackBottom"))
-    add(preMainCode, hcrGetProcLoadCode(m, "nimGC_setStackBottom", "nimrtl_", "rtl_handle", "nimGetProcAddr"))
-    add(preMainCode, "\tinner = PreMain;\L")
-    add(preMainCode, "\tinitStackBottomWith_actual((void *)&inner);\L")
-    add(preMainCode, "\t(*inner)();\L")
+    preMainCode.add(loadLib("hcr_handle", "hcrGetProc"))
+    preMainCode.add("\tvoid* rtl_handle;\L")
+    preMainCode.add(loadLib("rtl_handle", "nimGC_setStackBottom"))
+    preMainCode.add(hcrGetProcLoadCode(m, "nimGC_setStackBottom", "nimrtl_", "rtl_handle", "nimGetProcAddr"))
+    preMainCode.add("\tinner = PreMain;\L")
+    preMainCode.add("\tinitStackBottomWith_actual((void *)&inner);\L")
+    preMainCode.add("\t(*inner)();\L")
   else:
-    add(preMainCode, "\tPreMain();\L")
+    preMainCode.add("\tPreMain();\L")
 
   const
     # not a big deal if we always compile these 3 global vars... makes the HCR code easier
@@ -1465,63 +1464,63 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
     let systemModulePath = getModuleDllPath(m, g.modules[g.graph.config.m.systemFileIdx.int].module)
     let mainModulePath = getModuleDllPath(m, m.module)
     if sfMainModule in m.module.flags:
-      addf(hcrModuleMeta, "\t$1,$n", [systemModulePath])
+      hcrModuleMeta.addf("\t$1,$n", [systemModulePath])
     g.graph.importDeps.withValue(FileIndex(m.module.position), deps):
       for curr in deps[]:
-        addf(hcrModuleMeta, "\t$1,$n", [getModuleDllPath(m, g.modules[curr.int].module)])
-    addf(hcrModuleMeta, "\t\"\"};$n", [])
-    addf(hcrModuleMeta, "$nN_LIB_EXPORT N_NIMCALL(void**, HcrGetImportedModules)() { return (void**)hcr_module_list; }$n", [])
-    addf(hcrModuleMeta, "$nN_LIB_EXPORT N_NIMCALL(char*, HcrGetSigHash)() { return \"$1\"; }$n$n",
+        hcrModuleMeta.addf("\t$1,$n", [getModuleDllPath(m, g.modules[curr.int].module)])
+    hcrModuleMeta.addf("\t\"\"};$n", [])
+    hcrModuleMeta.addf("$nN_LIB_EXPORT N_NIMCALL(void**, HcrGetImportedModules)() { return (void**)hcr_module_list; }$n", [])
+    hcrModuleMeta.addf("$nN_LIB_EXPORT N_NIMCALL(char*, HcrGetSigHash)() { return \"$1\"; }$n$n",
                           [($sigHash(m.module)).rope])
     if sfMainModule in m.module.flags:
-      add(g.mainModProcs, hcrModuleMeta)
-      addf(g.mainModProcs, "static void* hcr_handle;$N", [])
-      addf(g.mainModProcs, "N_LIB_EXPORT N_NIMCALL(void, $1)(void);$N", [init])
-      addf(g.mainModProcs, "N_LIB_EXPORT N_NIMCALL(void, $1)(void);$N", [datInit])
-      addf(g.mainModProcs, "N_LIB_EXPORT N_NIMCALL(void, $1)(void*, N_NIMCALL_PTR(void*, getProcAddr)(void*, char*));$N", [m.getHcrInitName])
-      addf(g.mainModProcs, "N_LIB_EXPORT N_NIMCALL(void, HcrCreateTypeInfos)(void);$N", [])
-      addf(g.mainModInit, "\t$1();$N", [init])
-      addf(g.otherModsInit, "\thcrInit((void**)hcr_module_list, $1, $2, $3, hcr_handle, nimGetProcAddr);$n",
+      g.mainModProcs.add(hcrModuleMeta)
+      g.mainModProcs.addf("static void* hcr_handle;$N", [])
+      g.mainModProcs.addf("N_LIB_EXPORT N_NIMCALL(void, $1)(void);$N", [init])
+      g.mainModProcs.addf("N_LIB_EXPORT N_NIMCALL(void, $1)(void);$N", [datInit])
+      g.mainModProcs.addf("N_LIB_EXPORT N_NIMCALL(void, $1)(void*, N_NIMCALL_PTR(void*, getProcAddr)(void*, char*));$N", [m.getHcrInitName])
+      g.mainModProcs.addf("N_LIB_EXPORT N_NIMCALL(void, HcrCreateTypeInfos)(void);$N", [])
+      g.mainModInit.addf("\t$1();$N", [init])
+      g.otherModsInit.addf("\thcrInit((void**)hcr_module_list, $1, $2, $3, hcr_handle, nimGetProcAddr);$n",
                             [mainModulePath, systemModulePath, datInit])
-      addf(g.mainDatInit, "\t$1(hcr_handle, nimGetProcAddr);$N", [m.getHcrInitName])
-      addf(g.mainDatInit, "\thcrAddModule($1);\n", [mainModulePath])
-      addf(g.mainDatInit, "\tHcrCreateTypeInfos();$N", [])
+      g.mainDatInit.addf("\t$1(hcr_handle, nimGetProcAddr);$N", [m.getHcrInitName])
+      g.mainDatInit.addf("\thcrAddModule($1);\n", [mainModulePath])
+      g.mainDatInit.addf("\tHcrCreateTypeInfos();$N", [])
       # nasty nasty hack to get the command line functionality working with HCR
       # register the 2 variables on behalf of the os module which might not even
       # be loaded (in which case it will get collected but that is not a problem)
       let osModulePath = ($systemModulePath).replace("stdlib_system", "stdlib_os").rope
-      addf(g.mainDatInit, "\thcrAddModule($1);\n", [osModulePath])
-      add(g.mainDatInit, "\tint* cmd_count;\n")
-      add(g.mainDatInit, "\tchar*** cmd_line;\n")
-      addf(g.mainDatInit, "\thcrRegisterGlobal($1, \"cmdCount\", sizeof(cmd_count), NULL, (void**)&cmd_count);$N", [osModulePath])
-      addf(g.mainDatInit, "\thcrRegisterGlobal($1, \"cmdLine\", sizeof(cmd_line), NULL, (void**)&cmd_line);$N", [osModulePath])
-      add(g.mainDatInit, "\t*cmd_count = cmdCount;\n")
-      add(g.mainDatInit, "\t*cmd_line = cmdLine;\n")
+      g.mainDatInit.addf("\thcrAddModule($1);\n", [osModulePath])
+      g.mainDatInit.add("\tint* cmd_count;\n")
+      g.mainDatInit.add("\tchar*** cmd_line;\n")
+      g.mainDatInit.addf("\thcrRegisterGlobal($1, \"cmdCount\", sizeof(cmd_count), NULL, (void**)&cmd_count);$N", [osModulePath])
+      g.mainDatInit.addf("\thcrRegisterGlobal($1, \"cmdLine\", sizeof(cmd_line), NULL, (void**)&cmd_line);$N", [osModulePath])
+      g.mainDatInit.add("\t*cmd_count = cmdCount;\n")
+      g.mainDatInit.add("\t*cmd_line = cmdLine;\n")
     else:
-      add(m.s[cfsInitProc], hcrModuleMeta)
+      m.s[cfsInitProc].add(hcrModuleMeta)
     return
 
   if m.s[cfsDatInitProc].len > 0:
-    addf(g.mainModProcs, "N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [datInit])
-    addf(g.mainDatInit, "\t$1();$N", [datInit])
+    g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [datInit])
+    g.mainDatInit.addf("\t$1();$N", [datInit])
 
   # Initialization of TLS and GC should be done in between
   # systemDatInit and systemInit calls if any
   if sfSystemModule in m.module.flags:
     if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
-      add(g.mainDatInit, ropecg(m, "\t#initThreadVarsEmulation();$N", []))
+      g.mainDatInit.add(ropecg(m, "\t#initThreadVarsEmulation();$N", []))
     if m.config.target.targetOS != osStandalone and m.config.selectedGC != gcNone:
-      add(g.mainDatInit, ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", []))
+      g.mainDatInit.add(ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", []))
 
   if m.s[cfsInitProc].len > 0:
-    addf(g.mainModProcs, "N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [init])
+    g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [init])
     let initCall = "\t$1();$N" % [init]
     if sfMainModule in m.module.flags:
-      add(g.mainModInit, initCall)
+      g.mainModInit.add(initCall)
     elif sfSystemModule in m.module.flags:
-      add(g.mainDatInit, initCall) # systemInit must called right after systemDatInit if any
+      g.mainDatInit.add(initCall) # systemInit must called right after systemDatInit if any
     else:
-      add(g.otherModsInit, initCall)
+      g.otherModsInit.add(initCall)
 
 proc genDatInitCode(m: BModule) =
   ## this function is called in cgenWriteModules after all modules are closed,
@@ -1540,14 +1539,14 @@ proc genDatInitCode(m: BModule) =
   for i in cfsTypeInit1..cfsDynLibInit:
     if m.s[i].len != 0:
       moduleDatInitRequired = true
-      add(prc, genSectionStart(i, m.config))
-      add(prc, m.s[i])
-      add(prc, genSectionEnd(i, m.config))
+      prc.add(genSectionStart(i, m.config))
+      prc.add(m.s[i])
+      prc.add(genSectionEnd(i, m.config))
 
-  addf(prc, "}$N$N", [])
+  prc.addf("}$N$N", [])
 
   if moduleDatInitRequired:
-    add(m.s[cfsDatInitProc], prc)
+    m.s[cfsDatInitProc].add(prc)
 
 # Very similar to the contents of symInDynamicLib - basically only the
 # things needed for the hot code reloading runtime procs to be loaded
@@ -1562,7 +1561,7 @@ proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): R
   prc.typ.sym = nil
 
   if not containsOrIncl(m.declaredThings, prc.id):
-    addf(m.s[cfsVars], "static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t)])
+    m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t)])
 
   result = "\t$1 = ($2) $3($4, $5);$n" %
       [tmp, getTypeDesc(m, prc.typ), getProcFunc.rope, handle.rope, makeCString(prefix & sym)]
@@ -1591,7 +1590,7 @@ proc genInitCode(m: BModule) =
           [m.nimTypesName, m.nimTypes])
 
   if m.hcrOn:
-    addf(prc, "\tint* nim_hcr_dummy_ = 0;$n" &
+    prc.addf("\tint* nim_hcr_dummy_ = 0;$n" &
               "\tNIM_BOOL nim_hcr_do_init_ = " &
                   "hcrRegisterGlobal($1, \"module_initialized_\", 1, NULL, (void**)&nim_hcr_dummy_);$n",
       [getModuleDllPath(m, m.module)])
@@ -1599,29 +1598,29 @@ proc genInitCode(m: BModule) =
   template writeSection(thing: untyped, section: TCProcSection, addHcrGuards = false) =
     if m.thing.s(section).len > 0:
       moduleInitRequired = true
-      if addHcrGuards: add(prc, "\tif (nim_hcr_do_init_) {\n\n")
-      add(prc, genSectionStart(section, m.config))
-      add(prc, m.thing.s(section))
-      add(prc, genSectionEnd(section, m.config))
-      if addHcrGuards: add(prc, "\n\t} // nim_hcr_do_init_\n")
+      if addHcrGuards: prc.add("\tif (nim_hcr_do_init_) {\n\n")
+      prc.add(genSectionStart(section, m.config))
+      prc.add(m.thing.s(section))
+      prc.add(genSectionEnd(section, m.config))
+      if addHcrGuards: prc.add("\n\t} // nim_hcr_do_init_\n")
 
   if m.preInitProc.s(cpsInit).len > 0 or m.preInitProc.s(cpsStmts).len > 0:
     # Give this small function its own scope
-    addf(prc, "{$N", [])
+    prc.addf("{$N", [])
     # Keep a bogus frame in case the code needs one
-    add(prc, ~"\tTFrame FR_; FR_.len = 0;$N")
+    prc.add(~"\tTFrame FR_; FR_.len = 0;$N")
 
     writeSection(preInitProc, cpsLocals)
     writeSection(preInitProc, cpsInit, m.hcrOn)
     writeSection(preInitProc, cpsStmts)
-    addf(prc, "}$N", [])
+    prc.addf("}$N", [])
 
   # add new scope for following code, because old vcc compiler need variable
   # be defined at the top of the block
-  addf(prc, "{$N", [])
+  prc.addf("{$N", [])
   if m.initProc.gcFrameId > 0:
     moduleInitRequired = true
-    add(prc, initGCFrame(m.initProc))
+    prc.add(initGCFrame(m.initProc))
 
   writeSection(initProc, cpsLocals)
 
@@ -1633,22 +1632,22 @@ proc genInitCode(m: BModule) =
       incl m.flags, frameDeclared
       if preventStackTrace notin m.flags:
         var procname = makeCString(m.module.name.s)
-        add(prc, initFrame(m.initProc, procname, quotedFilename(m.config, m.module.info)))
+        prc.add(initFrame(m.initProc, procname, quotedFilename(m.config, m.module.info)))
       else:
-        add(prc, ~"\tTFrame FR_; FR_.len = 0;$N")
+        prc.add(~"\tTFrame FR_; FR_.len = 0;$N")
 
     writeSection(initProc, cpsInit, m.hcrOn)
     writeSection(initProc, cpsStmts)
 
     if optStackTrace in m.initProc.options and preventStackTrace notin m.flags:
-      add(prc, deinitFrame(m.initProc))
+      prc.add(deinitFrame(m.initProc))
 
   if m.initProc.gcFrameId > 0:
     moduleInitRequired = true
-    add(prc, deinitGCFrame(m.initProc))
-  addf(prc, "}$N", [])
+    prc.add(deinitGCFrame(m.initProc))
+  prc.addf("}$N", [])
 
-  addf(prc, "}$N$N", [])
+  prc.addf("}$N$N", [])
 
   # we cannot simply add the init proc to ``m.s[cfsProcs]`` anymore because
   # that would lead to a *nesting* of merge sections which the merger does
@@ -1657,32 +1656,32 @@ proc genInitCode(m: BModule) =
   if m.hcrOn:
     var procsToLoad = @["hcrRegisterProc", "hcrGetProc", "hcrRegisterGlobal", "hcrGetGlobal"]
 
-    addf(m.s[cfsInitProc], "N_LIB_EXPORT N_NIMCALL(void, $1)(void* handle, N_NIMCALL_PTR(void*, getProcAddr)(void*, char*)) {$N", [getHcrInitName(m)])
+    m.s[cfsInitProc].addf("N_LIB_EXPORT N_NIMCALL(void, $1)(void* handle, N_NIMCALL_PTR(void*, getProcAddr)(void*, char*)) {$N", [getHcrInitName(m)])
     if sfMainModule in m.module.flags:
       # additional procs to load
       procsToLoad.add("hcrInit")
       procsToLoad.add("hcrAddModule")
     # load procs
     for curr in procsToLoad:
-      add(m.s[cfsInitProc], hcrGetProcLoadCode(m, curr, "", "handle", "getProcAddr"))
-    addf(m.s[cfsInitProc], "}$N$N", [])
+      m.s[cfsInitProc].add(hcrGetProcLoadCode(m, curr, "", "handle", "getProcAddr"))
+    m.s[cfsInitProc].addf("}$N$N", [])
 
   for i, el in pairs(m.extensionLoaders):
     if el != nil:
       let ex = "NIM_EXTERNC N_NIMCALL(void, nimLoadProcs$1)(void) {$2}$N$N" %
         [(i.ord - '0'.ord).rope, el]
       moduleInitRequired = true
-      add(prc, ex)
+      prc.add(ex)
 
   if moduleInitRequired or sfMainModule in m.module.flags:
-    add(m.s[cfsInitProc], prc)
+    m.s[cfsInitProc].add(prc)
 
   genDatInitCode(m)
 
   if m.hcrOn:
-    addf(m.s[cfsInitProc], "N_LIB_EXPORT N_NIMCALL(void, HcrCreateTypeInfos)(void) {$N", [])
-    add(m.s[cfsInitProc], m.hcrCreateTypeInfosProc)
-    addf(m.s[cfsInitProc], "}$N$N", [])
+    m.s[cfsInitProc].addf("N_LIB_EXPORT N_NIMCALL(void, HcrCreateTypeInfos)(void) {$N", [])
+    m.s[cfsInitProc].add(m.hcrCreateTypeInfosProc)
+    m.s[cfsInitProc].addf("}$N$N", [])
 
   registerModuleToMain(m.g, m)
 
@@ -1694,31 +1693,31 @@ proc genModule(m: BModule, cfile: Cfile): Rope =
 
   generateThreadLocalStorage(m)
   generateHeaders(m)
-  add(result, genSectionStart(cfsHeaders, m.config))
-  add(result, m.s[cfsHeaders])
+  result.add(genSectionStart(cfsHeaders, m.config))
+  result.add(m.s[cfsHeaders])
   if m.config.cppCustomNamespace.len > 0:
     result.add openNamespaceNim(m.config.cppCustomNamespace)
-  add(result, genSectionEnd(cfsHeaders, m.config))
-  add(result, genSectionStart(cfsFrameDefines, m.config))
+  result.add(genSectionEnd(cfsHeaders, m.config))
+  result.add(genSectionStart(cfsFrameDefines, m.config))
   if m.s[cfsFrameDefines].len > 0:
-    add(result, m.s[cfsFrameDefines])
+    result.add(m.s[cfsFrameDefines])
   else:
-    add(result, "#define nimfr_(x, y)\n#define nimln_(x, y)\n")
-  add(result, genSectionEnd(cfsFrameDefines, m.config))
+    result.add("#define nimfr_(x, y)\n#define nimln_(x, y)\n")
+  result.add(genSectionEnd(cfsFrameDefines, m.config))
 
-  for i in cfsForwardTypes .. cfsProcs:
+  for i in cfsForwardTypes..cfsProcs:
     if m.s[i].len > 0:
       moduleIsEmpty = false
-      add(result, genSectionStart(i, m.config))
-      add(result, m.s[i])
-      add(result, genSectionEnd(i, m.config))
+      result.add(genSectionStart(i, m.config))
+      result.add(m.s[i])
+      result.add(genSectionEnd(i, m.config))
 
   if m.s[cfsInitProc].len > 0:
     moduleIsEmpty = false
-    add(result, m.s[cfsInitProc])
+    result.add(m.s[cfsInitProc])
   if m.s[cfsDatInitProc].len > 0 or m.hcrOn:
     moduleIsEmpty = false
-    add(result, m.s[cfsDatInitProc])
+    result.add(m.s[cfsDatInitProc])
 
   if m.config.cppCustomNamespace.len > 0:
     result.add closeNamespaceNim()
@@ -1803,12 +1802,12 @@ proc writeHeader(m: BModule) =
   generateHeaders(m)
 
   generateThreadLocalStorage(m)
-  for i in cfsHeaders .. cfsProcs:
-    add(result, genSectionStart(i, m.config))
-    add(result, m.s[i])
-    add(result, genSectionEnd(i, m.config))
+  for i in cfsHeaders..cfsProcs:
+    result.add(genSectionStart(i, m.config))
+    result.add(m.s[i])
+    result.add(genSectionEnd(i, m.config))
     if m.config.cppCustomNamespace.len > 0 and i == cfsHeaders: result.add openNamespaceNim(m.config.cppCustomNamespace)
-  add(result, m.s[cfsInitProc])
+  result.add(m.s[cfsInitProc])
 
   if optGenDynLib in m.config.globalOptions:
     result.add("N_LIB_IMPORT ")
@@ -1910,7 +1909,7 @@ proc writeModule(m: BModule, pending: bool) =
       if sfMainModule in m.module.flags:
         # generate main file:
         genMainProc(m)
-        add(m.s[cfsProcHeaders], m.g.mainModProcs)
+        m.s[cfsProcHeaders].add(m.g.mainModProcs)
         generateThreadVarsSize(m)
 
     var cf = Cfile(nimname: m.module.name.s, cname: cfile,
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index 6e451e953..9d128017e 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -172,7 +172,7 @@ proc includeHeader*(this: BModule; header: string) =
 
 proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} =
   # section in the current block
-  result = p.blocks[p.blocks.len-1].sections[s]
+  result = p.blocks[^1].sections[s]
 
 proc procSec*(p: BProc, s: TCProcSection): var Rope {.inline.} =
   # top level proc sections
diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim
index 180cfc334..f1fb1716a 100644
--- a/compiler/cgmeth.nim
+++ b/compiler/cgmeth.nim
@@ -23,11 +23,11 @@ proc genConv(n: PNode, d: PType, downcast: bool; conf: ConfigRef): PNode =
       result = n
     elif diff < 0:
       result = newNodeIT(nkObjUpConv, n.info, d)
-      addSon(result, n)
+      result.add n
       if downcast: internalError(conf, n.info, "cgmeth.genConv: no upcast allowed")
     elif diff > 0:
       result = newNodeIT(nkObjDownConv, n.info, d)
-      addSon(result, n)
+      result.add n
       if not downcast:
         internalError(conf, n.info, "cgmeth.genConv: no downcast allowed")
     else:
@@ -44,26 +44,26 @@ proc getDispatcher*(s: PSym): PSym =
 proc methodCall*(n: PNode; conf: ConfigRef): PNode =
   result = n
   # replace ordinary method by dispatcher method:
-  let disp = getDispatcher(result.sons[0].sym)
+  let disp = getDispatcher(result[0].sym)
   if disp != nil:
-    result.sons[0].sym = disp
+    result[0].sym = disp
     # change the arguments to up/downcasts to fit the dispatcher's parameters:
-    for i in 1 ..< len(result):
-      result.sons[i] = genConv(result.sons[i], disp.typ.sons[i], true, conf)
+    for i in 1..<result.len:
+      result[i] = genConv(result[i], disp.typ[i], true, conf)
   else:
-    localError(conf, n.info, "'" & $result.sons[0] & "' lacks a dispatcher")
+    localError(conf, n.info, "'" & $result[0] & "' lacks a dispatcher")
 
 type
   MethodResult = enum No, Invalid, Yes
 
 proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult =
   if a.name.id != b.name.id: return
-  if len(a.typ) != len(b.typ):
+  if a.typ.len != b.typ.len:
     return
 
-  for i in 1 ..< len(a.typ):
-    var aa = a.typ.sons[i]
-    var bb = b.typ.sons[i]
+  for i in 1..<a.typ.len:
+    var aa = a.typ[i]
+    var bb = b.typ[i]
     while true:
       aa = skipTypes(aa, {tyGenericInst, tyAlias})
       bb = skipTypes(bb, {tyGenericInst, tyAlias})
@@ -72,7 +72,7 @@ proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult =
         bb = bb.lastSon
       else:
         break
-    if sameType(a.typ.sons[i], b.typ.sons[i]):
+    if sameType(a.typ[i], b.typ[i]):
       if aa.kind == tyObject and result != Invalid:
         result = Yes
     elif aa.kind == tyObject and bb.kind == tyObject and (i == 1 or multiMethods):
@@ -90,22 +90,22 @@ proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult =
       return No
   if result == Yes:
     # check for return type:
-    if not sameTypeOrNil(a.typ.sons[0], b.typ.sons[0]):
-      if b.typ.sons[0] != nil and b.typ.sons[0].kind == tyUntyped:
+    if not sameTypeOrNil(a.typ[0], b.typ[0]):
+      if b.typ[0] != nil and b.typ[0].kind == tyUntyped:
         # infer 'auto' from the base to make it consistent:
-        b.typ.sons[0] = a.typ.sons[0]
+        b.typ[0] = a.typ[0]
       else:
         return No
 
 proc attachDispatcher(s: PSym, dispatcher: PNode) =
   if dispatcherPos < s.ast.len:
     # we've added a dispatcher already, so overwrite it
-    s.ast.sons[dispatcherPos] = dispatcher
+    s.ast[dispatcherPos] = dispatcher
   else:
     setLen(s.ast.sons, dispatcherPos+1)
     if s.ast[resultPos] == nil:
       s.ast[resultPos] = newNodeI(nkEmpty, s.info)
-    s.ast.sons[dispatcherPos] = dispatcher
+    s.ast[dispatcherPos] = dispatcher
 
 proc createDispatcher(s: PSym): PSym =
   var disp = copySym(s)
@@ -115,16 +115,16 @@ proc createDispatcher(s: PSym): PSym =
   # we can't inline the dispatcher itself (for now):
   if disp.typ.callConv == ccInline: disp.typ.callConv = ccDefault
   disp.ast = copyTree(s.ast)
-  disp.ast.sons[bodyPos] = newNodeI(nkEmpty, s.info)
+  disp.ast[bodyPos] = newNodeI(nkEmpty, s.info)
   disp.loc.r = nil
-  if s.typ.sons[0] != nil:
+  if s.typ[0] != nil:
     if disp.ast.len > resultPos:
-      disp.ast.sons[resultPos].sym = copySym(s.ast.sons[resultPos].sym)
+      disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym)
     else:
       # We've encountered a method prototype without a filled-in
       # resultPos slot. We put a placeholder in there that will
       # be updated in fixupDispatcher().
-      disp.ast.addSon(newNodeI(nkEmpty, s.info))
+      disp.ast.add newNodeI(nkEmpty, s.info)
   attachDispatcher(s, newSymNode(disp))
   # attach to itself to prevent bugs:
   attachDispatcher(disp, newSymNode(disp))
@@ -137,8 +137,8 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) =
   # the lock level of the dispatcher needs to be updated/checked
   # against that of the method.
   if disp.ast.len > resultPos and meth.ast.len > resultPos and
-     disp.ast.sons[resultPos].kind == nkEmpty:
-    disp.ast.sons[resultPos] = copyTree(meth.ast.sons[resultPos])
+     disp.ast[resultPos].kind == nkEmpty:
+    disp.ast[resultPos] = copyTree(meth.ast[resultPos])
 
   # The following code works only with lock levels, so we disable
   # it when they're not available.
@@ -158,13 +158,12 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) =
         disp.typ.lockLevel = meth.typ.lockLevel
 
 proc methodDef*(g: ModuleGraph; s: PSym, fromCache: bool) =
-  let L = len(g.methods)
   var witness: PSym
-  for i in 0 ..< L:
+  for i in 0..<g.methods.len:
     let disp = g.methods[i].dispatcher
     case sameMethodBucket(disp, s, multimethods = optMultiMethods in g.config.globalOptions)
     of Yes:
-      add(g.methods[i].methods, s)
+      g.methods[i].methods.add(s)
       attachDispatcher(s, disp.ast[dispatcherPos])
       fixupDispatcher(s, disp, g.config)
       #echo "fixup ", disp.name.s, " ", disp.id
@@ -178,7 +177,7 @@ proc methodDef*(g: ModuleGraph; s: PSym, fromCache: bool) =
     of Invalid:
       if witness.isNil: witness = g.methods[i].methods[0]
   # create a new dispatcher:
-  add(g.methods, (methods: @[s], dispatcher: createDispatcher(s)))
+  g.methods.add((methods: @[s], dispatcher: createDispatcher(s)))
   #echo "adding ", s.info
   #if fromCache:
   #  internalError(s.info, "no method dispatcher found")
@@ -190,32 +189,32 @@ proc methodDef*(g: ModuleGraph; s: PSym, fromCache: bool) =
 
 proc relevantCol(methods: seq[PSym], col: int): bool =
   # returns true iff the position is relevant
-  var t = methods[0].typ.sons[col].skipTypes(skipPtrs)
+  var t = methods[0].typ[col].skipTypes(skipPtrs)
   if t.kind == tyObject:
-    for i in 1 .. high(methods):
-      let t2 = skipTypes(methods[i].typ.sons[col], skipPtrs)
+    for i in 1..high(methods):
+      let t2 = skipTypes(methods[i].typ[col], skipPtrs)
       if not sameType(t2, t):
         return true
 
 proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
-  for col in 1 ..< len(a.typ):
+  for col in 1..<a.typ.len:
     if contains(relevantCols, col):
-      var aa = skipTypes(a.typ.sons[col], skipPtrs)
-      var bb = skipTypes(b.typ.sons[col], skipPtrs)
+      var aa = skipTypes(a.typ[col], skipPtrs)
+      var bb = skipTypes(b.typ[col], skipPtrs)
       var d = inheritanceDiff(aa, bb)
       if (d != high(int)) and d != 0:
         return d
 
 proc sortBucket(a: var seq[PSym], relevantCols: IntSet) =
   # we use shellsort here; fast and simple
-  var n = len(a)
+  var n = a.len
   var h = 1
   while true:
     h = 3 * h + 1
     if h > n: break
   while true:
     h = h div 3
-    for i in h ..< n:
+    for i in h..<n:
       var v = a[i]
       var j = i
       while cmpSignatures(a[j - h], v, relevantCols) >= 0:
@@ -228,71 +227,70 @@ proc sortBucket(a: var seq[PSym], relevantCols: IntSet) =
 proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet): PSym =
   var base = methods[0].ast[dispatcherPos].sym
   result = base
-  var paramLen = len(base.typ)
+  var paramLen = base.typ.len
   var nilchecks = newNodeI(nkStmtList, base.info)
   var disp = newNodeI(nkIfStmt, base.info)
   var ands = getSysMagic(g, unknownLineInfo(), "and", mAnd)
   var iss = getSysMagic(g, unknownLineInfo(), "of", mOf)
   let boolType = getSysType(g, unknownLineInfo(), tyBool)
-  for col in 1 ..< paramLen:
+  for col in 1..<paramLen:
     if contains(relevantCols, col):
-      let param = base.typ.n.sons[col].sym
+      let param = base.typ.n[col].sym
       if param.typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}:
-        addSon(nilchecks, newTree(nkCall,
-            newSymNode(getCompilerProc(g, "chckNilDisp")), newSymNode(param)))
-  for meth in 0 .. high(methods):
+        nilchecks.add newTree(nkCall,
+            newSymNode(getCompilerProc(g, "chckNilDisp")), newSymNode(param))
+  for meth in 0..high(methods):
     var curr = methods[meth]      # generate condition:
     var cond: PNode = nil
-    for col in 1 ..< paramLen:
+    for col in 1..<paramLen:
       if contains(relevantCols, col):
         var isn = newNodeIT(nkCall, base.info, boolType)
-        addSon(isn, newSymNode(iss))
-        let param = base.typ.n.sons[col].sym
-        addSon(isn, newSymNode(param))
-        addSon(isn, newNodeIT(nkType, base.info, curr.typ.sons[col]))
+        isn.add newSymNode(iss)
+        let param = base.typ.n[col].sym
+        isn.add newSymNode(param)
+        isn.add newNodeIT(nkType, base.info, curr.typ[col])
         if cond != nil:
           var a = newNodeIT(nkCall, base.info, boolType)
-          addSon(a, newSymNode(ands))
-          addSon(a, cond)
-          addSon(a, isn)
+          a.add newSymNode(ands)
+          a.add cond
+          a.add isn
           cond = a
         else:
           cond = isn
-    let retTyp = base.typ.sons[0]
+    let retTyp = base.typ[0]
     let call = newNodeIT(nkCall, base.info, retTyp)
-    addSon(call, newSymNode(curr))
-    for col in 1 ..< paramLen:
-      addSon(call, genConv(newSymNode(base.typ.n.sons[col].sym),
-                           curr.typ.sons[col], false, g.config))
+    call.add newSymNode(curr)
+    for col in 1..<paramLen:
+      call.add genConv(newSymNode(base.typ.n[col].sym),
+                           curr.typ[col], false, g.config)
     var ret: PNode
     if retTyp != nil:
       var a = newNodeI(nkFastAsgn, base.info)
-      addSon(a, newSymNode(base.ast.sons[resultPos].sym))
-      addSon(a, call)
+      a.add newSymNode(base.ast[resultPos].sym)
+      a.add call
       ret = newNodeI(nkReturnStmt, base.info)
-      addSon(ret, a)
+      ret.add a
     else:
       ret = call
     if cond != nil:
       var a = newNodeI(nkElifBranch, base.info)
-      addSon(a, cond)
-      addSon(a, ret)
-      addSon(disp, a)
+      a.add cond
+      a.add ret
+      disp.add a
     else:
       disp = ret
   nilchecks.add disp
   nilchecks.flags.incl nfTransf # should not be further transformed
-  result.ast.sons[bodyPos] = nilchecks
+  result.ast[bodyPos] = nilchecks
 
 proc generateMethodDispatchers*(g: ModuleGraph): PNode =
   result = newNode(nkStmtList)
-  for bucket in 0 ..< len(g.methods):
+  for bucket in 0..<g.methods.len:
     var relevantCols = initIntSet()
-    for col in 1 ..< len(g.methods[bucket].methods[0].typ):
+    for col in 1..<g.methods[bucket].methods[0].typ.len:
       if relevantCol(g.methods[bucket].methods, col): incl(relevantCols, col)
       if optMultiMethods notin g.config.globalOptions:
         # if multi-methods are not enabled, we are interested only in the first field
         break
     sortBucket(g.methods[bucket].methods, relevantCols)
-    addSon(result,
-           newSymNode(genDispatcher(g, g.methods[bucket].methods, relevantCols)))
+    result.add newSymNode(genDispatcher(g, g.methods[bucket].methods, relevantCols))
diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim
index 7d3637645..94e5086bb 100644
--- a/compiler/closureiters.nim
+++ b/compiler/closureiters.nim
@@ -237,7 +237,7 @@ proc toStmtList(n: PNode): PNode =
 proc addGotoOut(n: PNode, gotoOut: PNode): PNode =
   # Make sure `n` is a stmtlist, and ends with `gotoOut`
   result = toStmtList(n)
-  if result.len == 0 or result.sons[^1].kind != nkGotoState:
+  if result.len == 0 or result[^1].kind != nkGotoState:
     result.add(gotoOut)
 
 proc newTempVar(ctx: var Ctx, typ: PType): PSym =
@@ -273,7 +273,7 @@ proc transformBreaksAndContinuesInWhile(ctx: var Ctx, n: PNode, before, after: P
     if ctx.blockLevel == 0:
       result = after
   else:
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       n[i] = ctx.transformBreaksAndContinuesInWhile(n[i], before, after)
 
 proc transformBreaksInBlock(ctx: var Ctx, n: PNode, label, after: PNode): PNode =
@@ -293,7 +293,7 @@ proc transformBreaksInBlock(ctx: var Ctx, n: PNode, label, after: PNode): PNode
       if label.kind == nkSym and n[0].sym == label.sym:
         result = after
   else:
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       n[i] = ctx.transformBreaksInBlock(n[i], label, after)
 
 proc newNullifyCurExc(ctx: var Ctx, info: TLineInfo): PNode =
@@ -318,7 +318,7 @@ proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} =
 
       if c.len > 1:
         var cond: PNode
-        for i in 0 .. c.len - 2:
+        for i in 0..<c.len - 1:
           assert(c[i].kind == nkType)
           let nextCond = newTree(nkCall,
             newSymNode(g.getSysMagic(c.info, "of", mOf)),
@@ -401,7 +401,7 @@ proc exprToStmtList(n: PNode): tuple[s, res: PNode] =
   var n = n
   while n.kind == nkStmtListExpr:
     result.s.sons.add(n.sons)
-    result.s.sons.setLen(result.s.sons.len - 1) # delete last son
+    result.s.sons.setLen(result.s.len - 1) # delete last son
     n = n[^1]
 
   result.res = n
@@ -435,7 +435,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
 
   of nkYieldStmt:
     var ns = false
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       n[i] = ctx.lowerStmtListExprs(n[i], ns)
 
     if ns:
@@ -449,7 +449,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
 
   of nkPar, nkObjConstr, nkTupleConstr, nkBracket:
     var ns = false
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       n[i] = ctx.lowerStmtListExprs(n[i], ns)
 
     if ns:
@@ -459,7 +459,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
       if n.typ.isNil: internalError(ctx.g.config, "lowerStmtListExprs: constr typ.isNil")
       result.typ = n.typ
 
-      for i in 0 ..< n.len:
+      for i in 0..<n.len:
         case n[i].kind
         of nkExprColonExpr:
           if n[i][1].kind == nkStmtListExpr:
@@ -475,7 +475,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
 
   of nkIfStmt, nkIfExpr:
     var ns = false
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       n[i] = ctx.lowerStmtListExprs(n[i], ns)
 
     if ns:
@@ -541,7 +541,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
 
   of nkTryStmt, nkHiddenTryStmt:
     var ns = false
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       n[i] = ctx.lowerStmtListExprs(n[i], ns)
 
     if ns:
@@ -554,7 +554,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
         let tmp = ctx.newTempVar(n.typ)
 
         n[0] = ctx.convertExprBodyToAsgn(n[0], tmp)
-        for i in 1 ..< n.len:
+        for i in 1..<n.len:
           let branch = n[i]
           case branch.kind
           of nkExceptBranch:
@@ -571,7 +571,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
 
   of nkCaseStmt:
     var ns = false
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       n[i] = ctx.lowerStmtListExprs(n[i], ns)
 
     if ns:
@@ -589,7 +589,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
           result.add(st)
           n[0] = ex
 
-        for i in 1 ..< n.len:
+        for i in 1..<n.len:
           let branch = n[i]
           case branch.kind
           of nkOfBranch:
@@ -603,7 +603,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
 
   of nkCallKinds, nkChckRange, nkChckRangeF, nkChckRange64:
     var ns = false
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       n[i] = ctx.lowerStmtListExprs(n[i], ns)
 
     if ns:
@@ -643,7 +643,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
         result.add(ifNode)
         result.add(ctx.newEnvVarAccess(tmp))
       else:
-        for i in 0 ..< n.len:
+        for i in 0..<n.len:
           if n[i].kind == nkStmtListExpr:
             let (st, ex) = exprToStmtList(n[i])
             result.add(st)
@@ -672,7 +672,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
 
   of nkDiscardStmt, nkReturnStmt, nkRaiseStmt:
     var ns = false
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       n[i] = ctx.lowerStmtListExprs(n[i], ns)
 
     if ns:
@@ -686,7 +686,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
   of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv, nkObjDownConv,
       nkDerefExpr, nkHiddenDeref:
     var ns = false
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       n[i] = ctx.lowerStmtListExprs(n[i], ns)
 
     if ns:
@@ -700,7 +700,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
 
   of nkAsgn, nkFastAsgn:
     var ns = false
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       n[i] = ctx.lowerStmtListExprs(n[i], ns)
 
     if ns:
@@ -785,7 +785,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
       result.add(ex)
 
   else:
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       n[i] = ctx.lowerStmtListExprs(n[i], needsSplit)
 
 proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
@@ -849,7 +849,7 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode =
   of nkSkip:
     discard
   else:
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       n[i] = ctx.transformReturnsInTry(n[i])
 
 proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode =
@@ -859,14 +859,14 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
 
   of nkStmtList, nkStmtListExpr:
     result = addGotoOut(result, gotoOut)
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       if n[i].hasYields:
         # Create a new split
         let go = newNodeI(nkGotoState, n[i].info)
         n[i] = ctx.transformClosureIteratorBody(n[i], go)
 
         let s = newNodeI(nkStmtList, n[i + 1].info)
-        for j in i + 1 ..< n.len:
+        for j in i + 1..<n.len:
           s.add(n[j])
 
         n.sons.setLen(i + 1)
@@ -889,7 +889,7 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
     result[^1] = ctx.transformClosureIteratorBody(result[^1], gotoOut)
 
   of nkIfStmt, nkCaseStmt:
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       n[i] = ctx.transformClosureIteratorBody(n[i], gotoOut)
     if n[^1].kind != nkElse:
       # We don't have an else branch, but every possible branch has to end with
@@ -1001,7 +1001,7 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
     internalError(ctx.g.config, "closure iter " & $n.kind)
 
   else:
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       n[i] = ctx.transformClosureIteratorBody(n[i], gotoOut)
 
 proc stateFromGotoState(n: PNode): int =
@@ -1038,18 +1038,18 @@ proc transformStateAssignments(ctx: var Ctx, n: PNode): PNode =
       result.add(ctx.newStateAssgn(stateFromGotoState(n[1])))
 
       var retStmt = newNodeI(nkReturnStmt, n.info)
-      if n[0].sons[0].kind != nkEmpty:
-        var a = newNodeI(nkAsgn, n[0].sons[0].info)
-        var retVal = n[0].sons[0] #liftCapturedVars(n.sons[0], owner, d, c)
-        addSon(a, newSymNode(getClosureIterResult(ctx.g, ctx.fn)))
-        addSon(a, retVal)
+      if n[0][0].kind != nkEmpty:
+        var a = newNodeI(nkAsgn, n[0][0].info)
+        var retVal = n[0][0] #liftCapturedVars(n[0], owner, d, c)
+        a.add newSymNode(getClosureIterResult(ctx.g, ctx.fn))
+        a.add retVal
         retStmt.add(a)
       else:
         retStmt.add(ctx.g.emptyNode)
 
       result.add(retStmt)
     else:
-      for i in 0 ..< n.len:
+      for i in 0..<n.len:
         n[i] = ctx.transformStateAssignments(n[i])
 
   of nkSkip:
@@ -1069,7 +1069,7 @@ proc transformStateAssignments(ctx: var Ctx, n: PNode): PNode =
     result.add(breakState)
 
   else:
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       n[i] = ctx.transformStateAssignments(n[i])
 
 proc skipStmtList(ctx: Ctx; n: PNode): PNode =
@@ -1110,7 +1110,7 @@ proc skipThroughEmptyStates(ctx: var Ctx, n: PNode): PNode =
     result = copyTree(n)
     result[0].intVal = ctx.skipEmptyStates(result[0].intVal.int)
   else:
-    for i in 0 ..< n.len:
+    for i in 0..<n.len:
       n[i] = ctx.skipThroughEmptyStates(n[i])
 
 proc newArrayType(g: ModuleGraph; n: int, t: PType, owner: PSym): PType =
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 5e306288a..bb9356a17 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -110,7 +110,7 @@ proc writeCommandLineUsage*(conf: ConfigRef) =
   msgWriteln(conf, getCommandLineDesc(conf), {msgStdout})
 
 proc addPrefix(switch: string): string =
-  if len(switch) <= 1: result = "-" & switch
+  if switch.len <= 1: result = "-" & switch
   else: result = "--" & switch
 
 const
@@ -127,14 +127,14 @@ proc splitSwitch(conf: ConfigRef; switch: string, cmd, arg: var string, pass: TC
                  info: TLineInfo) =
   cmd = ""
   var i = 0
-  if i < len(switch) and switch[i] == '-': inc(i)
-  if i < len(switch) and switch[i] == '-': inc(i)
-  while i < len(switch):
+  if i < switch.len and switch[i] == '-': inc(i)
+  if i < switch.len and switch[i] == '-': inc(i)
+  while i < switch.len:
     case switch[i]
-    of 'a'..'z', 'A'..'Z', '0'..'9', '_', '.': add(cmd, switch[i])
+    of 'a'..'z', 'A'..'Z', '0'..'9', '_', '.': cmd.add(switch[i])
     else: break
     inc(i)
-  if i >= len(switch): arg = ""
+  if i >= switch.len: arg = ""
   # cmd:arg => (cmd,arg)
   elif switch[i] in {':', '='}: arg = substr(switch, i + 1)
   # cmd[sub]:rest => (cmd,[sub]:rest)
@@ -178,17 +178,17 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
   var i = 0
   var n = hintMin
   var isBracket = false
-  if i < len(arg) and arg[i] == '[':
+  if i < arg.len and arg[i] == '[':
     isBracket = true
     inc(i)
-  while i < len(arg) and (arg[i] notin {':', '=', ']'}):
-    add(id, arg[i])
+  while i < arg.len and (arg[i] notin {':', '=', ']'}):
+    id.add(arg[i])
     inc(i)
   if isBracket:
-    if i < len(arg) and arg[i] == ']': inc(i)
+    if i < arg.len and arg[i] == ']': inc(i)
     else: invalidCmdLineOption(conf, pass, orig, info)
 
-  if i < len(arg) and (arg[i] in {':', '='}): inc(i)
+  if i < arg.len and (arg[i] in {':', '='}): inc(i)
   else: invalidCmdLineOption(conf, pass, orig, info)
   if state == wHint:
     let x = findStr(lineinfos.HintsToStr, id)
diff --git a/compiler/depends.nim b/compiler/depends.nim
index 15d30dd5b..3d252c2a2 100644
--- a/compiler/depends.nim
+++ b/compiler/depends.nim
@@ -25,7 +25,7 @@ type
     dotGraph: Rope
 
 proc addDependencyAux(b: Backend; importing, imported: string) =
-  addf(b.dotGraph, "$1 -> \"$2\";$n", [rope(importing), rope(imported)])
+  b.dotGraph.addf("$1 -> \"$2\";$n", [rope(importing), rope(imported)])
   # s1 -> s2_4[label="[0-9]"];
 
 proc addDotDependency(c: PPassContext, n: PNode): PNode =
@@ -34,14 +34,14 @@ proc addDotDependency(c: PPassContext, n: PNode): PNode =
   let b = Backend(g.graph.backend)
   case n.kind
   of nkImportStmt:
-    for i in 0 ..< len(n):
-      var imported = getModuleName(g.config, n.sons[i])
+    for i in 0..<n.len:
+      var imported = getModuleName(g.config, n[i])
       addDependencyAux(b, g.module.name.s, imported)
   of nkFromStmt, nkImportExceptStmt:
-    var imported = getModuleName(g.config, n.sons[0])
+    var imported = getModuleName(g.config, n[0])
     addDependencyAux(b, g.module.name.s, imported)
   of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
-    for i in 0 ..< len(n): discard addDotDependency(c, n.sons[i])
+    for i in 0..<n.len: discard addDotDependency(c, n[i])
   else:
     discard
 
diff --git a/compiler/dfa.nim b/compiler/dfa.nim
index 4016820e6..c97e39460 100644
--- a/compiler/dfa.nim
+++ b/compiler/dfa.nim
@@ -331,20 +331,20 @@ when true:
     L4:
       join F1
     ]#
-    if isTrue(n.sons[0]):
+    if isTrue(n[0]):
       # 'while true' is an idiom in Nim and so we produce
       # better code for it:
       for i in 0..2:
         withBlock(nil):
-          c.gen(n.sons[1])
+          c.gen(n[1])
     else:
       let oldForksLen = c.forks.len
       var endings: array[3, TPosition]
       for i in 0..2:
         withBlock(nil):
-          c.gen(n.sons[0])
+          c.gen(n[0])
           endings[i] = c.forkI(n)
-          c.gen(n.sons[1])
+          c.gen(n[1])
       for i in countdown(endings.high, 0):
         let endPos = endings[i]
         c.patch(endPos)
@@ -363,20 +363,20 @@ else:
     let oldForksLen = c.forks.len
     let lab1 = c.genLabel
     withBlock(nil):
-      if isTrue(n.sons[0]):
-        c.gen(n.sons[1])
+      if isTrue(n[0]):
+        c.gen(n[1])
         c.jmpBack(n, lab1)
       else:
-        c.gen(n.sons[0])
+        c.gen(n[0])
         let lab2 = c.forkI(n)
-        c.gen(n.sons[1])
+        c.gen(n[1])
         c.jmpBack(n, lab1)
         c.patch(lab2)
     setLen(c.forks, oldForksLen)
 
 proc genBlock(c: var Con; n: PNode) =
-  withBlock(n.sons[0].sym):
-    c.gen(n.sons[1])
+  withBlock(n[0].sym):
+    c.gen(n[1])
 
 proc genJoins(c: var Con; n: PNode) =
   for i in countdown(c.forks.high, 0): joinI(c, c.forks[i], n)
@@ -384,10 +384,10 @@ proc genJoins(c: var Con; n: PNode) =
 proc genBreak(c: var Con; n: PNode) =
   genJoins(c, n)
   let lab1 = c.gotoI(n)
-  if n.sons[0].kind == nkSym:
-    #echo cast[int](n.sons[0].sym)
+  if n[0].kind == nkSym:
+    #echo cast[int](n[0].sym)
     for i in countdown(c.blocks.len-1, 0):
-      if c.blocks[i].label == n.sons[0].sym:
+      if c.blocks[i].label == n[0].sym:
         c.blocks[i].fixups.add lab1
         return
     #globalError(n.info, "VM problem: cannot find 'break' target")
@@ -441,13 +441,13 @@ proc genIf(c: var Con, n: PNode) =
   ]#
   let oldLen = c.forks.len
   var endings: seq[TPosition] = @[]
-  for i in 0 ..< len(n):
-    var it = n.sons[i]
-    c.gen(it.sons[0])
+  for i in 0..<n.len:
+    var it = n[i]
+    c.gen(it[0])
     if it.len == 2:
       let elsePos = forkI(c, it[1])
-      c.gen(it.sons[1])
-      endings.add(c.gotoI(it.sons[1]))
+      c.gen(it[1])
+      endings.add(c.gotoI(it[1]))
       c.patch(elsePos)
   for i in countdown(endings.high, 0):
     let endPos = endings[i]
@@ -461,9 +461,9 @@ proc genAndOr(c: var Con; n: PNode) =
   #   asgn dest, b
   # lab1:
   #   join F1
-  c.gen(n.sons[1])
+  c.gen(n[1])
   forkT(n):
-    c.gen(n.sons[2])
+    c.gen(n[2])
 
 proc genCase(c: var Con; n: PNode) =
   #  if (!expr1) goto lab1;
@@ -476,16 +476,16 @@ proc genCase(c: var Con; n: PNode) =
   #  lab2:
   #    elsePart
   #  Lend:
-  let isExhaustive = skipTypes(n.sons[0].typ,
+  let isExhaustive = skipTypes(n[0].typ,
     abstractVarRange-{tyTypeDesc}).kind notin {tyFloat..tyFloat128, tyString}
 
   var endings: seq[TPosition] = @[]
   let oldLen = c.forks.len
-  c.gen(n.sons[0])
-  for i in 1 ..< n.len:
-    let it = n.sons[i]
+  c.gen(n[0])
+  for i in 1..<n.len:
+    let it = n[i]
     if it.len == 1:
-      c.gen(it.sons[0])
+      c.gen(it[0])
     elif i == n.len-1 and isExhaustive:
       # treat the last branch as 'else' if this is an exhaustive case statement.
       c.gen(it.lastSon)
@@ -507,7 +507,7 @@ proc genTry(c: var Con; n: PNode) =
   let oldFixups = c.tryStmtFixups.len
 
   #let elsePos = c.forkI(n)
-  c.gen(n.sons[0])
+  c.gen(n[0])
   dec c.inTryStmt
   for i in oldFixups..c.tryStmtFixups.high:
     let f = c.tryStmtFixups[i]
@@ -520,10 +520,9 @@ proc genTry(c: var Con; n: PNode) =
   setLen(c.tryStmtFixups, oldFixups)
 
   #c.patch(elsePos)
-  for i in 1 ..< n.len:
-    let it = n.sons[i]
+  for i in 1..<n.len:
+    let it = n[i]
     if it.kind != nkFinally:
-      var blen = len(it)
       let endExcept = c.forkI(it)
       c.gen(it.lastSon)
       endings.add(c.gotoI(it))
@@ -538,7 +537,7 @@ proc genTry(c: var Con; n: PNode) =
 
   let fin = lastSon(n)
   if fin.kind == nkFinally:
-    c.gen(fin.sons[0])
+    c.gen(fin[0])
   doAssert(c.forks.len == oldLen)
 
 template genNoReturn(c: var Con; n: PNode) =
@@ -547,7 +546,7 @@ template genNoReturn(c: var Con; n: PNode) =
 
 proc genRaise(c: var Con; n: PNode) =
   genJoins(c, n)
-  gen(c, n.sons[0])
+  gen(c, n[0])
   if c.inTryStmt > 0:
     c.tryStmtFixups.add c.gotoI(n)
   else:
@@ -555,12 +554,12 @@ proc genRaise(c: var Con; n: PNode) =
 
 proc genImplicitReturn(c: var Con) =
   if c.owner.kind in {skProc, skFunc, skMethod, skIterator, skConverter} and resultPos < c.owner.ast.len:
-    gen(c, c.owner.ast.sons[resultPos])
+    gen(c, c.owner.ast[resultPos])
 
 proc genReturn(c: var Con; n: PNode) =
   genJoins(c, n)
-  if n.sons[0].kind != nkEmpty:
-    gen(c, n.sons[0])
+  if n[0].kind != nkEmpty:
+    gen(c, n[0])
   else:
     genImplicitReturn(c)
   genNoReturn(c, n)
@@ -695,7 +694,7 @@ proc genCall(c: var Con; n: PNode) =
   for i in 1..<n.len:
     gen(c, n[i])
     when false:
-      if t != nil and i < t.len and t.sons[i].kind == tyVar:
+      if t != nil and i < t.len and t[i].kind == tyVar:
         # This is wrong! Pass by var is a 'might def', not a 'must def'
         # like the other defs we emit. This is not good enough for a move
         # optimizer.
@@ -728,23 +727,23 @@ proc genVarSection(c: var Con; n: PNode) =
       discard
     elif a.kind == nkVarTuple:
       gen(c, a.lastSon)
-      for i in 0 .. a.len-3: genDef(c, a[i])
+      for i in 0..<a.len-2: genDef(c, a[i])
     else:
       gen(c, a.lastSon)
       if a.lastSon.kind != nkEmpty:
-        genDef(c, a.sons[0])
+        genDef(c, a[0])
 
 proc gen(c: var Con; n: PNode) =
   case n.kind
   of nkSym: genUse(c, n)
   of nkCallKinds:
-    if n.sons[0].kind == nkSym:
-      let s = n.sons[0].sym
+    if n[0].kind == nkSym:
+      let s = n[0].sym
       if s.magic != mNone:
         genMagic(c, n, s.magic)
       else:
         genCall(c, n)
-      if sfNoReturn in n.sons[0].sym.flags:
+      if sfNoReturn in n[0].sym.flags:
         genNoReturn(c, n)
     else:
       genCall(c, n)
@@ -760,7 +759,7 @@ proc gen(c: var Con; n: PNode) =
   of nkIfStmt, nkIfExpr: genIf(c, n)
   of nkWhenStmt:
     # This is "when nimvm" node. Chose the first branch.
-    gen(c, n.sons[0].sons[1])
+    gen(c, n[0][1])
   of nkCaseStmt: genCase(c, n)
   of nkWhileStmt: genWhile(c, n)
   of nkBlockExpr, nkBlockStmt: genBlock(c, n)
@@ -772,10 +771,10 @@ proc gen(c: var Con; n: PNode) =
      nkBracket, nkCurly, nkPar, nkTupleConstr, nkClosure, nkObjConstr, nkYieldStmt:
     for x in n: gen(c, x)
   of nkPragmaBlock: gen(c, n.lastSon)
-  of nkDiscardStmt, nkObjDownConv, nkObjUpConv: gen(c, n.sons[0])
+  of nkDiscardStmt, nkObjDownConv, nkObjUpConv: gen(c, n[0])
   of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast, nkHiddenSubConv, nkHiddenStdConv:
-    gen(c, n.sons[1])
-  of nkStringToCString, nkCStringToString: gen(c, n.sons[0])
+    gen(c, n[1])
+  of nkStringToCString, nkCStringToString: gen(c, n[0])
   of nkVarSection, nkLetSection: genVarSection(c, n)
   of nkDefer:
     doAssert false, "dfa construction pass requires the elimination of 'defer'"
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 1b51988b8..f75c16d02 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -50,12 +50,12 @@ proc whichType(d: PDoc; n: PNode): PSym =
     if d.types.strTableContains(n.sym):
       result = n.sym
   else:
-    for i in 0..<safeLen(n):
+    for i in 0..<n.safeLen:
       let x = whichType(d, n[i])
       if x != nil: return x
 
 proc attachToType(d: PDoc; p: PSym): PSym =
-  let params = p.ast.sons[paramsPos]
+  let params = p.ast[paramsPos]
   template check(i) =
     result = whichType(d, params[i])
     if result != nil: return result
@@ -68,7 +68,7 @@ proc attachToType(d: PDoc; p: PSym): PSym =
 
 template declareClosures =
   proc compilerMsgHandler(filename: string, line, col: int,
-                          msgKind: rst.MsgKind, arg: string) {.procvar, gcsafe.} =
+                          msgKind: rst.MsgKind, arg: string) {.gcsafe.} =
     # translate msg kind:
     var k: TMsgKind
     case msgKind
@@ -85,7 +85,7 @@ template declareClosures =
     {.gcsafe.}:
       globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg)
 
-  proc docgenFindFile(s: string): string {.procvar, gcsafe.} =
+  proc docgenFindFile(s: string): string {.gcsafe.} =
     result = options.findFile(conf, s).string
     if result.len == 0:
       result = getCurrentDir() / s
@@ -176,11 +176,11 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
   result.thisDir = result.destFile.splitFile.dir
 
 template dispA(conf: ConfigRef; dest: var Rope, xml, tex: string, args: openArray[Rope]) =
-  if conf.cmd != cmdRst2tex: addf(dest, xml, args)
-  else: addf(dest, tex, args)
+  if conf.cmd != cmdRst2tex: dest.addf(xml, args)
+  else: dest.addf(tex, args)
 
 proc getVarIdx(varnames: openArray[string], id: string): int =
-  for i in 0 .. high(varnames):
+  for i in 0..high(varnames):
     if cmpIgnoreStyle(varnames[i], id) == 0:
       return i
   result = -1
@@ -189,44 +189,43 @@ proc ropeFormatNamedVars(conf: ConfigRef; frmt: FormatStr,
                          varnames: openArray[string],
                          varvalues: openArray[Rope]): Rope =
   var i = 0
-  var L = len(frmt)
   result = nil
   var num = 0
-  while i < L:
+  while i < frmt.len:
     if frmt[i] == '$':
       inc(i)                  # skip '$'
       case frmt[i]
       of '#':
-        add(result, varvalues[num])
+        result.add(varvalues[num])
         inc(num)
         inc(i)
       of '$':
-        add(result, "$")
+        result.add("$")
         inc(i)
       of '0'..'9':
         var j = 0
         while true:
           j = (j * 10) + ord(frmt[i]) - ord('0')
           inc(i)
-          if (i > L + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
+          if (i > frmt.len + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
         if j > high(varvalues) + 1:
           rawMessage(conf, errGenerated, "Invalid format string; too many $s: " & frmt)
         num = j
-        add(result, varvalues[j - 1])
+        result.add(varvalues[j - 1])
       of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
         var id = ""
         while true:
-          add(id, frmt[i])
+          id.add(frmt[i])
           inc(i)
           if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break
         var idx = getVarIdx(varnames, id)
-        if idx >= 0: add(result, varvalues[idx])
+        if idx >= 0: result.add(varvalues[idx])
         else: rawMessage(conf, errGenerated, "unknown substition variable: " & id)
       of '{':
         var id = ""
         inc(i)
         while i < frmt.len and frmt[i] != '}':
-          add(id, frmt[i])
+          id.add(frmt[i])
           inc(i)
         if i >= frmt.len:
           rawMessage(conf, errGenerated, "expected closing '}'")
@@ -234,15 +233,15 @@ proc ropeFormatNamedVars(conf: ConfigRef; frmt: FormatStr,
           inc(i)                # skip }
         # search for the variable:
         let idx = getVarIdx(varnames, id)
-        if idx >= 0: add(result, varvalues[idx])
+        if idx >= 0: result.add(varvalues[idx])
         else: rawMessage(conf, errGenerated, "unknown substition variable: " & id)
       else:
-        add(result, "$")
+        result.add("$")
     var start = i
-    while i < L:
+    while i < frmt.len:
       if frmt[i] != '$': inc(i)
       else: break
-    if i - 1 >= start: add(result, substr(frmt, start, i - 1))
+    if i - 1 >= start: result.add(substr(frmt, start, i - 1))
 
 proc genComment(d: PDoc, n: PNode): string =
   result = ""
@@ -259,8 +258,8 @@ proc genRecCommentAux(d: PDoc, n: PNode): Rope =
     if n.kind in {nkStmtList, nkStmtListExpr, nkTypeDef, nkConstDef,
                   nkObjectTy, nkRefTy, nkPtrTy, nkAsgn, nkFastAsgn, nkHiddenStdConv}:
       # notin {nkEmpty..nkNilLit, nkEnumTy, nkTupleTy}:
-      for i in 0 ..< len(n):
-        result = genRecCommentAux(d, n.sons[i])
+      for i in 0..<n.len:
+        result = genRecCommentAux(d, n[i])
         if result != nil: return
   else:
     when defined(nimNoNilSeqs): n.comment = ""
@@ -287,8 +286,8 @@ proc getPlainDocstring(n: PNode): string =
   if startsWith(n.comment, "##"):
     result = n.comment
   if result.len < 1:
-    for i in 0 ..< safeLen(n):
-      result = getPlainDocstring(n.sons[i])
+    for i in 0..<n.safeLen:
+      result = getPlainDocstring(n[i])
       if result.len > 0: return
 
 proc belongsToPackage(conf: ConfigRef; module: PSym): bool =
@@ -358,7 +357,7 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
         dispA(d.conf, result, "<span class=\"Identifier\">$1</span>",
               "\\spanIdentifier{$1}", [rope(esc(d.target, literal))])
     of tkSpaces, tkInvalid:
-      add(result, literal)
+      result.add(literal)
     of tkCurlyDotLe:
       dispA(d.conf, result, "<span>" & # This span is required for the JS to work properly
         """<span class="Other">{</span><span class="Other pragmadots">...</span><span class="Other">}</span>
@@ -465,7 +464,7 @@ proc getAllRunnableExamplesRec(d: PDoc; n, orig: PNode; dest: var Rope) =
         nodeToHighlightedHtml(d, b, dest, {}, nil)
       dest.add(d.config.getOrDefault"doc.listing_end" % id)
   else: discard
-  for i in 0 ..< n.safeLen:
+  for i in 0..<n.safeLen:
     getAllRunnableExamplesRec(d, n[i], orig, dest)
 
 proc getAllRunnableExamples(d: PDoc; n: PNode; dest: var Rope) =
@@ -474,8 +473,8 @@ proc getAllRunnableExamples(d: PDoc; n: PNode; dest: var Rope) =
 proc isVisible(d: PDoc; n: PNode): bool =
   result = false
   if n.kind == nkPostfix:
-    if n.len == 2 and n.sons[0].kind == nkIdent:
-      var v = n.sons[0].ident
+    if n.len == 2 and n[0].kind == nkIdent:
+      var v = n[0].ident
       result = v.id == ord(wStar) or v.id == ord(wMinus)
   elif n.kind == nkSym:
     # we cannot generate code for forwarded symbols here as we have no
@@ -488,12 +487,12 @@ proc isVisible(d: PDoc; n: PNode): bool =
     if result and containsOrIncl(d.emitted, n.sym.id):
       result = false
   elif n.kind == nkPragmaExpr:
-    result = isVisible(d, n.sons[0])
+    result = isVisible(d, n[0])
 
 proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
   case n.kind
-  of nkPostfix: result = getName(d, n.sons[1], splitAfter)
-  of nkPragmaExpr: result = getName(d, n.sons[0], splitAfter)
+  of nkPostfix: result = getName(d, n[1], splitAfter)
+  of nkPragmaExpr: result = getName(d, n[0], splitAfter)
   of nkSym: result = esc(d.target, n.sym.renderDefinitionName, splitAfter)
   of nkIdent: result = esc(d.target, n.ident.s, splitAfter)
   of nkAccQuoted:
@@ -507,8 +506,8 @@ proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
 
 proc getNameIdent(cache: IdentCache; n: PNode): PIdent =
   case n.kind
-  of nkPostfix: result = getNameIdent(cache, n.sons[1])
-  of nkPragmaExpr: result = getNameIdent(cache, n.sons[0])
+  of nkPostfix: result = getNameIdent(cache, n[1])
+  of nkPragmaExpr: result = getNameIdent(cache, n[0])
   of nkSym: result = n.sym.name
   of nkIdent: result = n.ident
   of nkAccQuoted:
@@ -522,13 +521,13 @@ proc getNameIdent(cache: IdentCache; n: PNode): PIdent =
 
 proc getRstName(n: PNode): PRstNode =
   case n.kind
-  of nkPostfix: result = getRstName(n.sons[1])
-  of nkPragmaExpr: result = getRstName(n.sons[0])
+  of nkPostfix: result = getRstName(n[1])
+  of nkPragmaExpr: result = getRstName(n[0])
   of nkSym: result = newRstNode(rnLeaf, n.sym.renderDefinitionName)
   of nkIdent: result = newRstNode(rnLeaf, n.ident.s)
   of nkAccQuoted:
-    result = getRstName(n.sons[0])
-    for i in 1 ..< n.len: result.text.add(getRstName(n[i]).text)
+    result = getRstName(n[0])
+    for i in 1..<n.len: result.text.add(getRstName(n[i]).text)
   of nkOpenSymChoice, nkClosedSymChoice:
     result = getRstName(n[0])
   else:
@@ -573,7 +572,7 @@ proc complexName(k: TSymKind, n: PNode, baseName: string): string =
   of skTemplate: result.add(".t")
   of skConverter: result.add(".c")
   else: discard
-  if len(n) > paramsPos and n[paramsPos].kind == nkFormalParams:
+  if n.len > paramsPos and n[paramsPos].kind == nkFormalParams:
     let params = renderParamTypes(n[paramsPos])
     if params.len > 0:
       result.add(defaultParamSeparator)
@@ -653,8 +652,8 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
     plainName.add(literal)
 
   var pragmaNode: PNode = nil
-  if n.isCallable and n.sons[pragmasPos].kind != nkEmpty:
-    pragmaNode = findPragma(n.sons[pragmasPos], wDeprecated)
+  if n.isCallable and n[pragmasPos].kind != nkEmpty:
+    pragmaNode = findPragma(n[pragmasPos], wDeprecated)
 
   inc(d.id)
   let
@@ -680,7 +679,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
       let cwd = canonicalizePath(d.conf, getCurrentDir())
       var path = toFullPath(d.conf, n.info)
       if path.startsWith(cwd):
-        path = path[cwd.len+1 .. ^1].replace('\\', '/')
+        path = path[cwd.len+1..^1].replace('\\', '/')
     let gitUrl = getConfigVar(d.conf, "git.url")
     if gitUrl.len > 0:
       let defaultBranch =
@@ -692,7 +691,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
           ["path", "line", "url", "commit", "devel"], [rope path.string,
           rope($n.info.line), rope gitUrl, rope commit, rope develBranch])])
 
-  add(d.section[k], ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item"),
+  d.section[k].add(ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item"),
     ["name", "header", "desc", "itemID", "header_plain", "itemSym",
       "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "seeSrc", "deprecationMsg"],
     [nameRope, result, comm, itemIDRope, plainNameRope, plainSymbolRope,
@@ -715,7 +714,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
       setIndexTerm(d[], external, symbolOrId, plain, nameNode.sym.name.s & '.' & plain,
         xmltree.escape(getPlainDocstring(e).docstringSummary))
 
-  add(d.toc[k], ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item.toc"),
+  d.toc[k].add(ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item.toc"),
     ["name", "header", "desc", "itemID", "header_plain", "itemSym",
       "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "attype"],
     [rope(getName(d, nameNode, d.splitAfter)), result, comm,
@@ -761,11 +760,11 @@ proc traceDeps(d: PDoc, it: PNode) =
     a.add dir
     a.add sep # dummy entry, replaced in the loop
     for x in it[2]:
-      a.sons[2] = x
+      a[2] = x
       traceDeps(d, a)
   elif it.kind == nkSym and belongsToPackage(d.conf, it.sym):
     let external = externalDep(d, it.sym)
-    if d.section[k] != nil: add(d.section[k], ", ")
+    if d.section[k] != nil: d.section[k].add(", ")
     dispA(d.conf, d.section[k],
           "<a class=\"reference external\" href=\"$2\">$1</a>",
           "$1", [rope esc(d.target, changeFileExt(external, "")),
@@ -775,7 +774,7 @@ proc exportSym(d: PDoc; s: PSym) =
   const k = exportSection
   if s.kind == skModule and belongsToPackage(d.conf, s):
     let external = externalDep(d, s)
-    if d.section[k] != nil: add(d.section[k], ", ")
+    if d.section[k] != nil: d.section[k].add(", ")
     dispA(d.conf, d.section[k],
           "<a class=\"reference external\" href=\"$2\">$1</a>",
           "$1", [rope esc(d.target, changeFileExt(external, "")),
@@ -784,7 +783,7 @@ proc exportSym(d: PDoc; s: PSym) =
     let module = originatingModule(s)
     if belongsToPackage(d.conf, module):
       let external = externalDep(d, module)
-      if d.section[k] != nil: add(d.section[k], ", ")
+      if d.section[k] != nil: d.section[k].add(", ")
       # XXX proper anchor generation here
       dispA(d.conf, d.section[k],
             "<a href=\"$2#$1\"><span class=\"Identifier\">$1</span></a>",
@@ -792,37 +791,37 @@ proc exportSym(d: PDoc; s: PSym) =
             rope changeFileExt(external, "html")])
 
 proc documentNewEffect(cache: IdentCache; n: PNode): PNode =
-  let s = n.sons[namePos].sym
+  let s = n[namePos].sym
   if tfReturnsNew in s.typ.flags:
     result = newIdentNode(getIdent(cache, "new"), n.info)
 
 proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, idx: int): PNode =
   let spec = effectSpec(x, effectType)
   if isNil(spec):
-    let s = n.sons[namePos].sym
+    let s = n[namePos].sym
 
-    let actual = s.typ.n.sons[0]
+    let actual = s.typ.n[0]
     if actual.len != effectListLen: return
-    let real = actual.sons[idx]
+    let real = actual[idx]
 
     # warning: hack ahead:
     var effects = newNodeI(nkBracket, n.info, real.len)
-    for i in 0 ..< real.len:
+    for i in 0..<real.len:
       var t = typeToString(real[i].typ)
       if t.startsWith("ref "): t = substr(t, 4)
-      effects.sons[i] = newIdentNode(getIdent(cache, t), n.info)
+      effects[i] = newIdentNode(getIdent(cache, t), n.info)
       # set the type so that the following analysis doesn't screw up:
-      effects.sons[i].typ = real[i].typ
+      effects[i].typ = real[i].typ
 
     result = newNode(nkExprColonExpr, n.info, @[
       newIdentNode(getIdent(cache, specialWords[effectType]), n.info), effects])
 
 proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName: string): PNode =
-  let s = n.sons[namePos].sym
+  let s = n[namePos].sym
   let params = s.typ.n
 
   var effects = newNodeI(nkBracket, n.info)
-  for i in 1 ..< params.len:
+  for i in 1..<params.len:
     if params[i].kind == nkSym and flag in params[i].sym.flags:
       effects.add params[i]
 
@@ -831,8 +830,8 @@ proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName
       newIdentNode(getIdent(cache, pragmaName), n.info), effects])
 
 proc documentRaises*(cache: IdentCache; n: PNode) =
-  if n.sons[namePos].kind != nkSym: return
-  let pragmas = n.sons[pragmasPos]
+  if n[namePos].kind != nkSym: return
+  let pragmas = n[pragmasPos]
   let p1 = documentEffect(cache, n, pragmas, wRaises, exceptionEffects)
   let p2 = documentEffect(cache, n, pragmas, wTags, tagEffects)
   let p3 = documentWriteEffect(cache, n, sfWrittenTo, "writes")
@@ -841,59 +840,59 @@ proc documentRaises*(cache: IdentCache; n: PNode) =
 
   if p1 != nil or p2 != nil or p3 != nil or p4 != nil or p5 != nil:
     if pragmas.kind == nkEmpty:
-      n.sons[pragmasPos] = newNodeI(nkPragma, n.info)
-    if p1 != nil: n.sons[pragmasPos].add p1
-    if p2 != nil: n.sons[pragmasPos].add p2
-    if p3 != nil: n.sons[pragmasPos].add p3
-    if p4 != nil: n.sons[pragmasPos].add p4
-    if p5 != nil: n.sons[pragmasPos].add p5
+      n[pragmasPos] = newNodeI(nkPragma, n.info)
+    if p1 != nil: n[pragmasPos].add p1
+    if p2 != nil: n[pragmasPos].add p2
+    if p3 != nil: n[pragmasPos].add p3
+    if p4 != nil: n[pragmasPos].add p4
+    if p5 != nil: n[pragmasPos].add p5
 
 proc generateDoc*(d: PDoc, n, orig: PNode) =
   case n.kind
   of nkPragma:
     let pragmaNode = findPragma(n, wDeprecated)
-    add(d.modDeprecationMsg, genDeprecationMsg(d, pragmaNode))
-  of nkCommentStmt: add(d.modDesc, genComment(d, n))
+    d.modDeprecationMsg.add(genDeprecationMsg(d, pragmaNode))
+  of nkCommentStmt: d.modDesc.add(genComment(d, n))
   of nkProcDef:
     when useEffectSystem: documentRaises(d.cache, n)
-    genItem(d, n, n.sons[namePos], skProc)
+    genItem(d, n, n[namePos], skProc)
   of nkFuncDef:
     when useEffectSystem: documentRaises(d.cache, n)
-    genItem(d, n, n.sons[namePos], skFunc)
+    genItem(d, n, n[namePos], skFunc)
   of nkMethodDef:
     when useEffectSystem: documentRaises(d.cache, n)
-    genItem(d, n, n.sons[namePos], skMethod)
+    genItem(d, n, n[namePos], skMethod)
   of nkIteratorDef:
     when useEffectSystem: documentRaises(d.cache, n)
-    genItem(d, n, n.sons[namePos], skIterator)
-  of nkMacroDef: genItem(d, n, n.sons[namePos], skMacro)
-  of nkTemplateDef: genItem(d, n, n.sons[namePos], skTemplate)
+    genItem(d, n, n[namePos], skIterator)
+  of nkMacroDef: genItem(d, n, n[namePos], skMacro)
+  of nkTemplateDef: genItem(d, n, n[namePos], skTemplate)
   of nkConverterDef:
     when useEffectSystem: documentRaises(d.cache, n)
-    genItem(d, n, n.sons[namePos], skConverter)
+    genItem(d, n, n[namePos], skConverter)
   of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
-    for i in 0 ..< len(n):
-      if n.sons[i].kind != nkCommentStmt:
+    for i in 0..<n.len:
+      if n[i].kind != nkCommentStmt:
         # order is always 'type var let const':
-        genItem(d, n.sons[i], n.sons[i].sons[0],
+        genItem(d, n[i], n[i][0],
                 succ(skType, ord(n.kind)-ord(nkTypeSection)))
   of nkStmtList:
-    for i in 0 ..< len(n): generateDoc(d, n.sons[i], orig)
+    for i in 0..<n.len: generateDoc(d, n[i], orig)
   of nkWhenStmt:
     # generate documentation for the first branch only:
-    if not checkForFalse(n.sons[0].sons[0]):
-      generateDoc(d, lastSon(n.sons[0]), orig)
+    if not checkForFalse(n[0][0]):
+      generateDoc(d, lastSon(n[0]), orig)
   of nkImportStmt:
     for it in n: traceDeps(d, it)
   of nkExportStmt:
     for it in n:
       if it.kind == nkSym: exportSym(d, it.sym)
   of nkExportExceptStmt: discard "transformed into nkExportStmt by semExportExcept"
-  of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
+  of nkFromStmt, nkImportExceptStmt: traceDeps(d, n[0])
   of nkCallKinds:
     var comm: Rope = nil
     getAllRunnableExamples(d, n, comm)
-    if comm != nil: add(d.modDesc, comm)
+    if comm != nil: d.modDesc.add(comm)
   else: discard
 
 proc add(d: PDoc; j: JsonNode) =
@@ -905,39 +904,39 @@ proc generateJson*(d: PDoc, n: PNode, includeComments: bool = true) =
     if includeComments:
       d.add %*{"comment": genComment(d, n)}
     else:
-      add(d.modDesc, genComment(d, n))
+      d.modDesc.add(genComment(d, n))
   of nkProcDef:
     when useEffectSystem: documentRaises(d.cache, n)
-    d.add genJsonItem(d, n, n.sons[namePos], skProc)
+    d.add genJsonItem(d, n, n[namePos], skProc)
   of nkFuncDef:
     when useEffectSystem: documentRaises(d.cache, n)
-    d.add genJsonItem(d, n, n.sons[namePos], skFunc)
+    d.add genJsonItem(d, n, n[namePos], skFunc)
   of nkMethodDef:
     when useEffectSystem: documentRaises(d.cache, n)
-    d.add genJsonItem(d, n, n.sons[namePos], skMethod)
+    d.add genJsonItem(d, n, n[namePos], skMethod)
   of nkIteratorDef:
     when useEffectSystem: documentRaises(d.cache, n)
-    d.add genJsonItem(d, n, n.sons[namePos], skIterator)
+    d.add genJsonItem(d, n, n[namePos], skIterator)
   of nkMacroDef:
-    d.add genJsonItem(d, n, n.sons[namePos], skMacro)
+    d.add genJsonItem(d, n, n[namePos], skMacro)
   of nkTemplateDef:
-    d.add genJsonItem(d, n, n.sons[namePos], skTemplate)
+    d.add genJsonItem(d, n, n[namePos], skTemplate)
   of nkConverterDef:
     when useEffectSystem: documentRaises(d.cache, n)
-    d.add genJsonItem(d, n, n.sons[namePos], skConverter)
+    d.add genJsonItem(d, n, n[namePos], skConverter)
   of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
-    for i in 0 ..< len(n):
-      if n.sons[i].kind != nkCommentStmt:
+    for i in 0..<n.len:
+      if n[i].kind != nkCommentStmt:
         # order is always 'type var let const':
-        d.add genJsonItem(d, n.sons[i], n.sons[i].sons[0],
+        d.add genJsonItem(d, n[i], n[i][0],
                 succ(skType, ord(n.kind)-ord(nkTypeSection)))
   of nkStmtList:
-    for i in 0 ..< len(n):
-      generateJson(d, n.sons[i], includeComments)
+    for i in 0..<n.len:
+      generateJson(d, n[i], includeComments)
   of nkWhenStmt:
     # generate documentation for the first branch only:
-    if not checkForFalse(n.sons[0].sons[0]):
-      generateJson(d, lastSon(n.sons[0]), includeComments)
+    if not checkForFalse(n[0][0]):
+      generateJson(d, lastSon(n[0]), includeComments)
   else: discard
 
 proc genTagsItem(d: PDoc, n, nameNode: PNode, k: TSymKind): string =
@@ -951,36 +950,36 @@ proc generateTags*(d: PDoc, n: PNode, r: var Rope) =
       r.add stripped
   of nkProcDef:
     when useEffectSystem: documentRaises(d.cache, n)
-    r.add genTagsItem(d, n, n.sons[namePos], skProc)
+    r.add genTagsItem(d, n, n[namePos], skProc)
   of nkFuncDef:
     when useEffectSystem: documentRaises(d.cache, n)
-    r.add genTagsItem(d, n, n.sons[namePos], skFunc)
+    r.add genTagsItem(d, n, n[namePos], skFunc)
   of nkMethodDef:
     when useEffectSystem: documentRaises(d.cache, n)
-    r.add genTagsItem(d, n, n.sons[namePos], skMethod)
+    r.add genTagsItem(d, n, n[namePos], skMethod)
   of nkIteratorDef:
     when useEffectSystem: documentRaises(d.cache, n)
-    r.add genTagsItem(d, n, n.sons[namePos], skIterator)
+    r.add genTagsItem(d, n, n[namePos], skIterator)
   of nkMacroDef:
-    r.add genTagsItem(d, n, n.sons[namePos], skMacro)
+    r.add genTagsItem(d, n, n[namePos], skMacro)
   of nkTemplateDef:
-    r.add genTagsItem(d, n, n.sons[namePos], skTemplate)
+    r.add genTagsItem(d, n, n[namePos], skTemplate)
   of nkConverterDef:
     when useEffectSystem: documentRaises(d.cache, n)
-    r.add genTagsItem(d, n, n.sons[namePos], skConverter)
+    r.add genTagsItem(d, n, n[namePos], skConverter)
   of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
-    for i in 0 ..< len(n):
-      if n.sons[i].kind != nkCommentStmt:
+    for i in 0..<n.len:
+      if n[i].kind != nkCommentStmt:
         # order is always 'type var let const':
-        r.add genTagsItem(d, n.sons[i], n.sons[i].sons[0],
+        r.add genTagsItem(d, n[i], n[i][0],
                 succ(skType, ord(n.kind)-ord(nkTypeSection)))
   of nkStmtList:
-    for i in 0 ..< len(n):
-      generateTags(d, n.sons[i], r)
+    for i in 0..<n.len:
+      generateTags(d, n[i], r)
   of nkWhenStmt:
     # generate documentation for the first branch only:
-    if not checkForFalse(n.sons[0].sons[0]):
-      generateTags(d, lastSon(n.sons[0]), r)
+    if not checkForFalse(n[0][0]):
+      generateTags(d, lastSon(n[0]), r)
   else: discard
 
 proc genSection(d: PDoc, kind: TSymKind) =
@@ -1005,12 +1004,12 @@ proc genOutFile(d: PDoc): Rope =
   var tmp = ""
   renderTocEntries(d[], j, 1, tmp)
   var toc = tmp.rope
-  for i in low(TSymKind) .. high(TSymKind):
+  for i in low(TSymKind)..high(TSymKind):
     genSection(d, i)
-    add(toc, d.toc[i])
+    toc.add(d.toc[i])
   if toc != nil:
     toc = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.toc"), ["content"], [toc])
-  for i in low(TSymKind) .. high(TSymKind): add(code, d.section[i])
+  for i in low(TSymKind)..high(TSymKind): code.add(d.section[i])
 
   # Extract the title. Non API modules generate an entry in the index table.
   if d.meta[metaTitle].len != 0:
diff --git a/compiler/enumtostr.nim b/compiler/enumtostr.nim
index 930cf24c4..35bf64a49 100644
--- a/compiler/enumtostr.nim
+++ b/compiler/enumtostr.nim
@@ -13,7 +13,7 @@ proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph): PSym =
   result.typ = newType(tyProc, t.owner)
   result.typ.n = newNodeI(nkFormalParams, info)
   rawAddSon(result.typ, res.typ)
-  addSon(result.typ.n, newNodeI(nkEffectList, info))
+  result.typ.n.add newNodeI(nkEffectList, info)
 
   result.typ.addParam dest
 
@@ -22,7 +22,7 @@ proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph): PSym =
   caseStmt.add(newSymNode dest)
 
   # copy the branches over, but replace the fields with the for loop body:
-  for i in 0 ..< t.n.len:
+  for i in 0..<t.n.len:
     assert(t.n[i].kind == nkSym)
     var field = t.n[i].sym
     let val = if field.ast == nil: field.name.s else: field.ast.strVal
@@ -33,11 +33,11 @@ proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph): PSym =
   body.add(caseStmt)
 
   var n = newNodeI(nkProcDef, info, bodyPos+2)
-  for i in 0 ..< n.len: n.sons[i] = newNodeI(nkEmpty, info)
-  n.sons[namePos] = newSymNode(result)
-  n.sons[paramsPos] = result.typ.n
-  n.sons[bodyPos] = body
-  n.sons[resultPos] = newSymNode(res)
+  for i in 0..<n.len: n[i] = newNodeI(nkEmpty, info)
+  n[namePos] = newSymNode(result)
+  n[paramsPos] = result.typ.n
+  n[bodyPos] = body
+  n[resultPos] = newSymNode(res)
   result.ast = n
   incl result.flags, sfFromGeneric
 
@@ -67,7 +67,7 @@ proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGra
   result.typ = newType(tyProc, t.owner)
   result.typ.n = newNodeI(nkFormalParams, info)
   rawAddSon(result.typ, res.typ)
-  addSon(result.typ.n, newNodeI(nkEffectList, info))
+  result.typ.n.add newNodeI(nkEffectList, info)
 
   result.typ.addParam dest
 
@@ -77,10 +77,10 @@ proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGra
 
   let subObj = searchObjCase(t.n, field)
   doAssert subObj != nil
-  for i in 1 ..< subObj.len:
+  for i in 1..<subObj.len:
     let ofBranch = subObj[i]
     var newBranch = newNodeI(ofBranch.kind, ofBranch.info)
-    for j in 0..ofBranch.len-2:
+    for j in 0..<ofBranch.len-1:
       newBranch.add ofBranch[j]
 
     newBranch.add newTree(nkStmtList, newTree(nkFastAsgn, newSymNode(res), newIntNode(nkInt8Lit, i)))
@@ -89,10 +89,10 @@ proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGra
   body.add(caseStmt)
 
   var n = newNodeI(nkProcDef, info, bodyPos+2)
-  for i in 0 ..< n.len: n.sons[i] = newNodeI(nkEmpty, info)
-  n.sons[namePos] = newSymNode(result)
-  n.sons[paramsPos] = result.typ.n
-  n.sons[bodyPos] = body
-  n.sons[resultPos] = newSymNode(res)
+  for i in 0..<n.len: n[i] = newNodeI(nkEmpty, info)
+  n[namePos] = newSymNode(result)
+  n[paramsPos] = result.typ.n
+  n[bodyPos] = body
+  n[resultPos] = newSymNode(res)
   result.ast = n
   incl result.flags, sfFromGeneric
diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim
index 6b9346c64..543810886 100644
--- a/compiler/evalffi.nim
+++ b/compiler/evalffi.nim
@@ -94,7 +94,7 @@ proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.TType =
      tyTyped, tyTypeDesc, tyProc, tyArray, tyStatic, tyNil:
     result = addr libffi.type_pointer
   of tyDistinct, tyAlias, tySink:
-    result = mapType(conf, t.sons[0])
+    result = mapType(conf, t[0])
   else:
     result = nil
   # too risky:
@@ -120,16 +120,16 @@ proc packSize(conf: ConfigRef, v: PNode, typ: PType): int =
     if v.kind in {nkNilLit, nkPtrLit}:
       result = sizeof(pointer)
     else:
-      result = sizeof(pointer) + packSize(conf, v.sons[0], typ.lastSon)
+      result = sizeof(pointer) + packSize(conf, v[0], typ.lastSon)
   of tyDistinct, tyGenericInst, tyAlias, tySink:
-    result = packSize(conf, v, typ.sons[0])
+    result = packSize(conf, v, typ[0])
   of tyArray:
     # consider: ptr array[0..1000_000, int] which is common for interfacing;
     # we use the real length here instead
     if v.kind in {nkNilLit, nkPtrLit}:
       result = sizeof(pointer)
     elif v.len != 0:
-      result = v.len * packSize(conf, v.sons[0], typ.sons[1])
+      result = v.len * packSize(conf, v[0], typ[1])
   else:
     result = getSize(conf, typ).int
 
@@ -138,16 +138,16 @@ proc pack(conf: ConfigRef, v: PNode, typ: PType, res: pointer)
 proc getField(conf: ConfigRef, n: PNode; position: int): PSym =
   case n.kind
   of nkRecList:
-    for i in 0 ..< len(n):
-      result = getField(conf, n.sons[i], position)
+    for i in 0..<n.len:
+      result = getField(conf, n[i], position)
       if result != nil: return
   of nkRecCase:
-    result = getField(conf, n.sons[0], position)
+    result = getField(conf, n[0], position)
     if result != nil: return
-    for i in 1 ..< len(n):
-      case n.sons[i].kind
+    for i in 1..<n.len:
+      case n[i].kind
       of nkOfBranch, nkElse:
-        result = getField(conf, lastSon(n.sons[i]), position)
+        result = getField(conf, lastSon(n[i]), position)
         if result != nil: return
       else: internalError(conf, n.info, "getField(record case branch)")
   of nkSym:
@@ -158,12 +158,12 @@ proc packObject(conf: ConfigRef, x: PNode, typ: PType, res: pointer) =
   internalAssert conf, x.kind in {nkObjConstr, nkPar, nkTupleConstr}
   # compute the field's offsets:
   discard getSize(conf, typ)
-  for i in ord(x.kind == nkObjConstr) ..< len(x):
-    var it = x.sons[i]
+  for i in ord(x.kind == nkObjConstr)..<x.len:
+    var it = x[i]
     if it.kind == nkExprColonExpr:
-      internalAssert conf, it.sons[0].kind == nkSym
-      let field = it.sons[0].sym
-      pack(conf, it.sons[1], field.typ, res +! field.offset)
+      internalAssert conf, it[0].kind == nkSym
+      let field = it[0].sym
+      pack(conf, it[1], field.typ, res +! field.offset)
     elif typ.n != nil:
       let field = getField(conf, typ.n, i)
       pack(conf, it, field.typ, res +! field.offset)
@@ -224,19 +224,19 @@ proc pack(conf: ConfigRef, v: PNode, typ: PType, res: pointer) =
         packRecCheck = 0
         globalError(conf, v.info, "cannot map value to FFI " & typeToString(v.typ))
       inc packRecCheck
-      pack(conf, v.sons[0], typ.lastSon, res +! sizeof(pointer))
+      pack(conf, v[0], typ.lastSon, res +! sizeof(pointer))
       dec packRecCheck
       awr(pointer, res +! sizeof(pointer))
   of tyArray:
-    let baseSize = getSize(conf, typ.sons[1])
-    for i in 0 ..< v.len:
-      pack(conf, v.sons[i], typ.sons[1], res +! i * baseSize)
+    let baseSize = getSize(conf, typ[1])
+    for i in 0..<v.len:
+      pack(conf, v[i], typ[1], res +! i * baseSize)
   of tyObject, tyTuple:
     packObject(conf, v, typ, res)
   of tyNil:
     discard
   of tyDistinct, tyGenericInst, tyAlias, tySink:
-    pack(conf, v, typ.sons[0], res)
+    pack(conf, v, typ[0], res)
   else:
     globalError(conf, v.info, "cannot map value to FFI " & typeToString(v.typ))
 
@@ -245,14 +245,14 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode
 proc unpackObjectAdd(conf: ConfigRef, x: pointer, n, result: PNode) =
   case n.kind
   of nkRecList:
-    for i in 0 ..< len(n):
-      unpackObjectAdd(conf, x, n.sons[i], result)
+    for i in 0..<n.len:
+      unpackObjectAdd(conf, x, n[i], result)
   of nkRecCase:
     globalError(conf, result.info, "case objects cannot be unpacked")
   of nkSym:
     var pair = newNodeI(nkExprColonExpr, result.info, 2)
-    pair.sons[0] = n
-    pair.sons[1] = unpack(conf, x +! n.sym.offset, n.sym.typ, nil)
+    pair[0] = n
+    pair[1] = unpack(conf, x +! n.sym.offset, n.sym.typ, nil)
     #echo "offset: ", n.sym.name.s, " ", n.sym.offset
     result.add pair
   else: discard
@@ -275,15 +275,15 @@ proc unpackObject(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
       globalError(conf, n.info, "cannot map value from FFI")
     if typ.n.isNil:
       globalError(conf, n.info, "cannot unpack unnamed tuple")
-    for i in ord(n.kind == nkObjConstr) ..< len(n):
-      var it = n.sons[i]
+    for i in ord(n.kind == nkObjConstr)..<n.len:
+      var it = n[i]
       if it.kind == nkExprColonExpr:
-        internalAssert conf, it.sons[0].kind == nkSym
-        let field = it.sons[0].sym
-        it.sons[1] = unpack(conf, x +! field.offset, field.typ, it.sons[1])
+        internalAssert conf, it[0].kind == nkSym
+        let field = it[0].sym
+        it[1] = unpack(conf, x +! field.offset, field.typ, it[1])
       else:
         let field = getField(conf, typ.n, i)
-        n.sons[i] = unpack(conf, x +! field.offset, field.typ, it)
+        n[i] = unpack(conf, x +! field.offset, field.typ, it)
 
 proc unpackArray(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
   if n.isNil:
@@ -294,9 +294,9 @@ proc unpackArray(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
     result = n
     if result.kind != nkBracket:
       globalError(conf, n.info, "cannot map value from FFI")
-  let baseSize = getSize(conf, typ.sons[1])
-  for i in 0 ..< result.len:
-    result.sons[i] = unpack(conf, x +! i * baseSize, typ.sons[1], result.sons[i])
+  let baseSize = getSize(conf, typ[1])
+  for i in 0..<result.len:
+    result[i] = unpack(conf, x +! i * baseSize, typ[1], result[i])
 
 proc canonNodeKind(k: TNodeKind): TNodeKind =
   case k
@@ -376,7 +376,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
       awi(nkPtrLit, cast[ByteAddress](p))
     elif n != nil and n.len == 1:
       internalAssert(conf, n.kind == nkRefTy)
-      n.sons[0] = unpack(conf, p, typ.lastSon, n.sons[0])
+      n[0] = unpack(conf, p, typ.lastSon, n[0])
       result = n
     else:
       globalError(conf, n.info, "cannot map value from FFI " & typeToString(typ))
@@ -419,41 +419,41 @@ proc fficast*(conf: ConfigRef, x: PNode, destTyp: PType): PNode =
     dealloc a
 
 proc callForeignFunction*(conf: ConfigRef, call: PNode): PNode =
-  internalAssert conf, call.sons[0].kind == nkPtrLit
+  internalAssert conf, call[0].kind == nkPtrLit
 
   var cif: TCif
   var sig: TParamList
   # use the arguments' types for varargs support:
-  for i in 1..call.len-1:
-    sig[i-1] = mapType(conf, call.sons[i].typ)
+  for i in 1..<call.len:
+    sig[i-1] = mapType(conf, call[i].typ)
     if sig[i-1].isNil:
       globalError(conf, call.info, "cannot map FFI type")
 
-  let typ = call.sons[0].typ
+  let typ = call[0].typ
   if prep_cif(cif, mapCallConv(conf, typ.callConv, call.info), cuint(call.len-1),
-              mapType(conf, typ.sons[0]), sig) != OK:
+              mapType(conf, typ[0]), sig) != OK:
     globalError(conf, call.info, "error in FFI call")
 
   var args: TArgList
-  let fn = cast[pointer](call.sons[0].intVal)
-  for i in 1 .. call.len-1:
-    var t = call.sons[i].typ
-    args[i-1] = alloc0(packSize(conf, call.sons[i], t))
-    pack(conf, call.sons[i], t, args[i-1])
-  let retVal = if isEmptyType(typ.sons[0]): pointer(nil)
-               else: alloc(getSize(conf, typ.sons[0]).int)
+  let fn = cast[pointer](call[0].intVal)
+  for i in 1..<call.len:
+    var t = call[i].typ
+    args[i-1] = alloc0(packSize(conf, call[i], t))
+    pack(conf, call[i], t, args[i-1])
+  let retVal = if isEmptyType(typ[0]): pointer(nil)
+               else: alloc(getSize(conf, typ[0]).int)
 
   libffi.call(cif, fn, retVal, args)
 
   if retVal.isNil:
     result = newNode(nkEmpty)
   else:
-    result = unpack(conf, retVal, typ.sons[0], nil)
+    result = unpack(conf, retVal, typ[0], nil)
     result.info = call.info
 
   if retVal != nil: dealloc retVal
-  for i in 1 .. call.len-1:
-    call.sons[i] = unpack(conf, args[i-1], typ.sons[i], call[i])
+  for i in 1..<call.len:
+    call[i] = unpack(conf, args[i-1], typ[i], call[i])
     dealloc args[i-1]
 
 proc callForeignFunction*(conf: ConfigRef, fn: PNode, fntyp: PType,
@@ -467,34 +467,34 @@ proc callForeignFunction*(conf: ConfigRef, fn: PNode, fntyp: PType,
     var aTyp = args[i+start].typ
     if aTyp.isNil:
       internalAssert conf, i+1 < fntyp.len
-      aTyp = fntyp.sons[i+1]
+      aTyp = fntyp[i+1]
       args[i+start].typ = aTyp
     sig[i] = mapType(conf, aTyp)
     if sig[i].isNil: globalError(conf, info, "cannot map FFI type")
 
   if prep_cif(cif, mapCallConv(conf, fntyp.callConv, info), cuint(len),
-              mapType(conf, fntyp.sons[0]), sig) != OK:
+              mapType(conf, fntyp[0]), sig) != OK:
     globalError(conf, info, "error in FFI call")
 
   var cargs: TArgList
   let fn = cast[pointer](fn.intVal)
-  for i in 0 .. len-1:
+  for i in 0..len-1:
     let t = args[i+start].typ
     cargs[i] = alloc0(packSize(conf, args[i+start], t))
     pack(conf, args[i+start], t, cargs[i])
-  let retVal = if isEmptyType(fntyp.sons[0]): pointer(nil)
-               else: alloc(getSize(conf, fntyp.sons[0]).int)
+  let retVal = if isEmptyType(fntyp[0]): pointer(nil)
+               else: alloc(getSize(conf, fntyp[0]).int)
 
   libffi.call(cif, fn, retVal, cargs)
 
   if retVal.isNil:
     result = newNode(nkEmpty)
   else:
-    result = unpack(conf, retVal, fntyp.sons[0], nil)
+    result = unpack(conf, retVal, fntyp[0], nil)
     result.info = info
 
   if retVal != nil: dealloc retVal
-  for i in 0 .. len-1:
+  for i in 0..len-1:
     let t = args[i+start].typ
     args[i+start] = unpack(conf, cargs[i], t, args[i+start])
     dealloc cargs[i]
diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim
index 90e309f80..2a01a7911 100644
--- a/compiler/evaltempl.nim
+++ b/compiler/evaltempl.nim
@@ -39,10 +39,10 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
     var s = templ.sym
     if (s.owner == nil and s.kind == skParam) or s.owner == c.owner:
       if s.kind == skParam and {sfGenSym, sfTemplateParam} * s.flags == {sfTemplateParam}:
-        handleParam actual.sons[s.position]
+        handleParam actual[s.position]
       elif (s.owner != nil) and (s.kind == skGenericParam or
            s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam):
-        handleParam actual.sons[s.owner.typ.len + s.position - 1]
+        handleParam actual[s.owner.typ.len + s.position - 1]
       else:
         internalAssert c.config, sfGenSym in s.flags or s.kind == skType
         var x = PSym(idTableGet(c.mapping, s))
@@ -68,8 +68,8 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
     # "declarative" context (bug #9235).
     if c.isDeclarative:
       var res = copyNode(c, templ, actual)
-      for i in 0 ..< len(templ):
-        evalTemplateAux(templ.sons[i], actual, c, res)
+      for i in 0..<templ.len:
+        evalTemplateAux(templ[i], actual, c, res)
       result.add res
     else:
       result.add newNodeI(nkEmpty, templ.info)
@@ -82,8 +82,8 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
       c.isDeclarative = true
       isDeclarative = true
     var res = copyNode(c, templ, actual)
-    for i in 0 ..< len(templ):
-      evalTemplateAux(templ.sons[i], actual, c, res)
+    for i in 0..<templ.len:
+      evalTemplateAux(templ[i], actual, c, res)
     result.add res
     if isDeclarative: c.isDeclarative = false
 
@@ -122,22 +122,22 @@ proc evalTemplateArgs(n: PNode, s: PSym; conf: ConfigRef; fromHlo: bool): PNode
                 n.renderTree)
 
   result = newNodeI(nkArgList, n.info)
-  for i in 1 .. givenRegularParams:
-    result.addSon n[i]
+  for i in 1..givenRegularParams:
+    result.add n[i]
 
   # handle parameters with default values, which were
   # not supplied by the user
-  for i in givenRegularParams+1 .. expectedRegularParams:
-    let default = s.typ.n.sons[i].sym.ast
+  for i in givenRegularParams+1..expectedRegularParams:
+    let default = s.typ.n[i].sym.ast
     if default.isNil or default.kind == nkEmpty:
       localError(conf, n.info, errWrongNumberOfArguments)
-      addSon(result, newNodeI(nkEmpty, n.info))
+      result.add newNodeI(nkEmpty, n.info)
     else:
-      addSon(result, default.copyTree)
+      result.add default.copyTree
 
   # add any generic parameters
-  for i in 1 .. genericParams:
-    result.addSon n.sons[givenRegularParams + i]
+  for i in 1..genericParams:
+    result.add n[givenRegularParams + i]
 
 # to prevent endless recursion in template instantiation
 const evalTemplateLimit* = 1000
@@ -155,7 +155,7 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
       if x.kind in nkCallKinds:
         for i in 1..<x.len:
           if x[i].kind in nkCallKinds:
-            x.sons[i].info = info
+            x[i].info = info
   else:
     result = newNodeI(nkStmtListExpr, info)
     var d = newNodeI(nkComesFrom, info)
@@ -187,7 +187,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
   if isAtom(body):
     result = newNodeI(nkPar, body.info)
     evalTemplateAux(body, args, ctx, result)
-    if result.len == 1: result = result.sons[0]
+    if result.len == 1: result = result[0]
     else:
       localError(conf, result.info, "illformed AST: " &
                   renderTree(result, {renderNoComments}))
@@ -196,8 +196,8 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
     ctx.instLines = sfCallsite in tmpl.flags
     if ctx.instLines:
       result.info = n.info
-    for i in 0 ..< safeLen(body):
-      evalTemplateAux(body.sons[i], args, ctx, result)
+    for i in 0..<body.safeLen:
+      evalTemplateAux(body[i], args, ctx, result)
   result.flags.incl nfFromTemplate
   result = wrapInComesFrom(n.info, tmpl, result)
   #if ctx.debugActive:
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index 711ca8737..0eaba4600 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -384,13 +384,13 @@ proc libNameTmpl(conf: ConfigRef): string {.inline.} =
 proc nameToCC*(name: string): TSystemCC =
   ## Returns the kind of compiler referred to by `name`, or ccNone
   ## if the name doesn't refer to any known compiler.
-  for i in succ(ccNone) .. high(TSystemCC):
+  for i in succ(ccNone)..high(TSystemCC):
     if cmpIgnoreStyle(name, CC[i].name) == 0:
       return i
   result = ccNone
 
 proc listCCnames(): seq[string] =
-  for i in succ(ccNone) .. high(TSystemCC):
+  for i in succ(ccNone)..high(TSystemCC):
     result.add CC[i].name
 
 proc isVSCompatible*(conf: ConfigRef): bool =
@@ -431,12 +431,12 @@ proc setCC*(conf: ConfigRef; ccname: string; info: TLineInfo) =
   conf.compileOptions = getConfigVar(conf, conf.cCompiler, ".options.always")
   conf.linkOptions = ""
   conf.cCompilerPath = getConfigVar(conf, conf.cCompiler, ".path")
-  for i in low(CC) .. high(CC): undefSymbol(conf.symbols, CC[i].name)
+  for i in low(CC)..high(CC): undefSymbol(conf.symbols, CC[i].name)
   defineSymbol(conf.symbols, CC[conf.cCompiler].name)
 
 proc addOpt(dest: var string, src: string) =
-  if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ")
-  add(dest, src)
+  if dest.len == 0 or dest[^1] != ' ': dest.add(" ")
+  dest.add(src)
 
 proc addLinkOption*(conf: ConfigRef; option: string) =
   addOpt(conf.linkOptions, option)
@@ -453,11 +453,11 @@ proc addCompileOptionCmd*(conf: ConfigRef; option: string) =
 
 proc initVars*(conf: ConfigRef) =
   # we need to define the symbol here, because ``CC`` may have never been set!
-  for i in low(CC) .. high(CC): undefSymbol(conf.symbols, CC[i].name)
+  for i in low(CC)..high(CC): undefSymbol(conf.symbols, CC[i].name)
   defineSymbol(conf.symbols, CC[conf.cCompiler].name)
   addCompileOption(conf, getConfigVar(conf, conf.cCompiler, ".options.always"))
   #addLinkOption(getConfigVar(cCompiler, ".options.linker"))
-  if len(conf.cCompilerPath) == 0:
+  if conf.cCompilerPath.len == 0:
     conf.cCompilerPath = getConfigVar(conf, conf.cCompiler, ".path")
 
 proc completeCfilePath*(conf: ConfigRef; cfile: AbsoluteFile,
@@ -607,7 +607,7 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile,
   if needsExeExt(conf): exe = addFileExt(exe, "exe")
   if (optGenDynLib in conf.globalOptions or (conf.hcrOn and not isMainFile)) and
       ospNeedsPIC in platform.OS[conf.target.targetOS].props:
-    add(options, ' ' & CC[c].pic)
+    options.add(' ' & CC[c].pic)
 
   var includeCmd, compilePattern: string
   if not noAbsolutePaths(conf):
@@ -660,8 +660,8 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile,
         rawMessage(conf, hintUserRaw, "Couldn't produce assembler listing " &
           "for the selected C compiler: " & CC[conf.cCompiler].name)
 
-  add(result, ' ')
-  addf(result, CC[c].compileTmpl, [
+  result.add(' ')
+  result.addf(CC[c].compileTmpl, [
     "dfile", dfile,
     "file", cfsh, "objfile", quoteShell(objfile),
     "options", options, "include", includeCmd,
@@ -720,12 +720,12 @@ proc compileCFiles(conf: ConfigRef; list: CfileList, script: var Rope, cmds: var
     var compileCmd = getCompileCFileCmd(conf, it, currIdx == list.len - 1, produceOutput=true)
     inc currIdx
     if optCompileOnly notin conf.globalOptions:
-      add(cmds, compileCmd)
+      cmds.add(compileCmd)
       let (_, name, _) = splitFile(it.cname)
-      add(prettyCmds, if hintCC in conf.notes: "CC: " & demanglePackageName(name) else: "")
+      prettyCmds.add(if hintCC in conf.notes: "CC: " & demanglePackageName(name) else: "")
     if optGenScript in conf.globalOptions:
-      add(script, compileCmd)
-      add(script, "\n")
+      script.add(compileCmd)
+      script.add("\n")
 
 proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile,
                 objfiles: string, isDllBuild: bool): string =
@@ -741,7 +741,7 @@ proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile,
                                             "objfiles", objfiles]
   else:
     var linkerExe = getConfigVar(conf, conf.cCompiler, ".linkerexe")
-    if len(linkerExe) == 0: linkerExe = getLinkerExe(conf, conf.cCompiler)
+    if linkerExe.len == 0: linkerExe = getLinkerExe(conf, conf.cCompiler)
     # bug #6452: We must not use ``quoteShell`` here for ``linkerExe``
     if needsExeExt(conf): linkerExe = addFileExt(linkerExe, "exe")
     if noAbsolutePaths(conf): result = linkerExe
@@ -771,7 +771,7 @@ proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile,
         "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
         "exefile", exefile, "nim", getPrefixDir(conf).string, "lib", conf.libpath.string])
     result.add ' '
-    addf(result, linkTmpl, ["builddll", builddll,
+    result.addf(linkTmpl, ["builddll", builddll,
         "mapfile", mapfile,
         "buildgui", buildgui, "options", linkOptions,
         "objfiles", objfiles, "exefile", exefile,
@@ -849,7 +849,7 @@ proc execCmdsInParallel(conf: ConfigRef; cmds: seq[string]; prettyCb: proc (idx:
   if conf.numberOfProcessors == 0: conf.numberOfProcessors = countProcessors()
   var res = 0
   if conf.numberOfProcessors <= 1:
-    for i in 0 .. high(cmds):
+    for i in 0..high(cmds):
       tryExceptOSErrorMessage(conf, "invocation of external compiler program failed."):
         res = execWithEcho(conf, cmds[i])
       if res != 0:
@@ -929,8 +929,8 @@ proc callCCompiler*(conf: ConfigRef) =
     var objfiles = ""
     for it in conf.externalToLink:
       let objFile = if noAbsolutePaths(conf): it.extractFilename else: it
-      add(objfiles, ' ')
-      add(objfiles, quoteShell(
+      objfiles.add(' ')
+      objfiles.add(quoteShell(
           addFileExt(objFile, CC[conf.cCompiler].objExt)))
 
     if conf.hcrOn: # lets assume that optCompileOnly isn't on
@@ -947,7 +947,7 @@ proc callCCompiler*(conf: ConfigRef) =
         let objFile = conf.getObjFilePath(x)
         let buildDll = idx != mainFileIdx
         let linkTarget = conf.hcrLinkTargetName(objFile, not buildDll)
-        add(cmds, getLinkCmd(conf, linkTarget, objfiles & " " & quoteShell(objFile), buildDll))
+        cmds.add(getLinkCmd(conf, linkTarget, objfiles & " " & quoteShell(objFile), buildDll))
         # try to remove all .pdb files for the current binary so they don't accumulate endlessly in the nimcache
         # for more info check the comment inside of getLinkCmd() where the /PDB:<filename> MSVC flag is used
         if isVSCompatible(conf):
@@ -966,8 +966,8 @@ proc callCCompiler*(conf: ConfigRef) =
     else:
       for x in conf.toCompile:
         let objFile = if noAbsolutePaths(conf): x.obj.extractFilename else: x.obj.string
-        add(objfiles, ' ')
-        add(objfiles, quoteShell(objFile))
+        objfiles.add(' ')
+        objfiles.add(quoteShell(objFile))
       let mainOutput = if optGenScript notin conf.globalOptions: conf.prepareToWriteOutput
                        else: AbsoluteFile(conf.projectName)
       linkCmd = getLinkCmd(conf, mainOutput, objfiles)
@@ -983,8 +983,8 @@ proc callCCompiler*(conf: ConfigRef) =
   else:
     linkCmd = ""
   if optGenScript in conf.globalOptions:
-    add(script, linkCmd)
-    add(script, "\n")
+    script.add(linkCmd)
+    script.add("\n")
     generateScript(conf, script)
 
 #from json import escapeJson
@@ -1022,16 +1022,16 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) =
       let objfile = if noAbsolutePaths(conf): it.extractFilename
                     else: it
       let objstr = addFileExt(objfile, CC[conf.cCompiler].objExt)
-      add(objfiles, ' ')
-      add(objfiles, objstr)
+      objfiles.add(' ')
+      objfiles.add(objstr)
       if pastStart: lit ",\L"
       str objstr
       pastStart = true
 
     for it in clist:
       let objstr = quoteShell(it.obj)
-      add(objfiles, ' ')
-      add(objfiles, objstr)
+      objfiles.add(' ')
+      objfiles.add(objstr)
       if pastStart: lit ",\L"
       str objstr
       pastStart = true
@@ -1120,9 +1120,9 @@ proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile) =
       doAssert c.kind == JArray
       doAssert c.len >= 2
 
-      add(cmds, c[1].getStr)
+      cmds.add(c[1].getStr)
       let (_, name, _) = splitFile(c[0].getStr)
-      add(prettyCmds, "CC: " & demanglePackageName(name))
+      prettyCmds.add("CC: " & demanglePackageName(name))
 
     let prettyCb = proc (idx: int) =
       when declared(echo):
@@ -1139,23 +1139,23 @@ proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: AbsoluteFile) =
 
 proc genMappingFiles(conf: ConfigRef; list: CfileList): Rope =
   for it in list:
-    addf(result, "--file:r\"$1\"$N", [rope(it.cname.string)])
+    result.addf("--file:r\"$1\"$N", [rope(it.cname.string)])
 
 proc writeMapping*(conf: ConfigRef; symbolMapping: Rope) =
   if optGenMapping notin conf.globalOptions: return
   var code = rope("[C_Files]\n")
-  add(code, genMappingFiles(conf, conf.toCompile))
-  add(code, "\n[C_Compiler]\nFlags=")
-  add(code, strutils.escape(getCompileOptions(conf)))
+  code.add(genMappingFiles(conf, conf.toCompile))
+  code.add("\n[C_Compiler]\nFlags=")
+  code.add(strutils.escape(getCompileOptions(conf)))
 
-  add(code, "\n[Linker]\nFlags=")
-  add(code, strutils.escape(getLinkOptions(conf) & " " &
+  code.add("\n[Linker]\nFlags=")
+  code.add(strutils.escape(getLinkOptions(conf) & " " &
                             getConfigVar(conf, conf.cCompiler, ".options.linker")))
 
-  add(code, "\n[Environment]\nlibpath=")
-  add(code, strutils.escape(conf.libpath.string))
+  code.add("\n[Environment]\nlibpath=")
+  code.add(strutils.escape(conf.libpath.string))
 
-  addf(code, "\n[Symbols]$n$1", [symbolMapping])
+  code.addf("\n[Symbols]$n$1", [symbolMapping])
   let filename = conf.projectPath / RelativeFile"mapping.txt"
   if not writeRope(code, filename):
     rawMessage(conf, errGenerated, "could not write to file: " & filename.string)
diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim
index 54218d73c..1d95369a8 100644
--- a/compiler/filter_tmpl.nim
+++ b/compiler/filter_tmpl.nim
@@ -75,7 +75,7 @@ proc parseLine(p: var TTmplParser) =
     let d = j
     var keyw = ""
     while j < len and p.x[j] in PatternChars:
-      add(keyw, p.x[j])
+      keyw.add(p.x[j])
       inc(j)
 
     scanPar(p, j)
diff --git a/compiler/filters.nim b/compiler/filters.nim
index 36fd25f2f..8151c0b93 100644
--- a/compiler/filters.nim
+++ b/compiler/filters.nim
@@ -20,13 +20,13 @@ proc invalidPragma(conf: ConfigRef; n: PNode) =
 proc getArg(conf: ConfigRef; n: PNode, name: string, pos: int): PNode =
   result = nil
   if n.kind in {nkEmpty..nkNilLit}: return
-  for i in 1 ..< len(n):
-    if n.sons[i].kind == nkExprEqExpr:
-      if n.sons[i].sons[0].kind != nkIdent: invalidPragma(conf, n)
-      if cmpIgnoreStyle(n.sons[i].sons[0].ident.s, name) == 0:
-        return n.sons[i].sons[1]
+  for i in 1..<n.len:
+    if n[i].kind == nkExprEqExpr:
+      if n[i][0].kind != nkIdent: invalidPragma(conf, n)
+      if cmpIgnoreStyle(n[i][0].ident.s, name) == 0:
+        return n[i][1]
     elif i == pos:
-      return n.sons[i]
+      return n[i]
 
 proc charArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: char): char =
   var x = getArg(conf, n, name, pos)
@@ -55,7 +55,7 @@ proc filterStrip*(conf: ConfigRef; stdin: PLLStream, filename: AbsoluteFile, cal
   var line = newStringOfCap(80)
   while llStreamReadLine(stdin, line):
     var stripped = strip(line, leading, trailing)
-    if len(pattern) == 0 or startsWith(stripped, pattern):
+    if pattern.len == 0 or startsWith(stripped, pattern):
       llStreamWriteln(result, stripped)
     else:
       llStreamWriteln(result, line)
@@ -63,7 +63,7 @@ proc filterStrip*(conf: ConfigRef; stdin: PLLStream, filename: AbsoluteFile, cal
 
 proc filterReplace*(conf: ConfigRef; stdin: PLLStream, filename: AbsoluteFile, call: PNode): PLLStream =
   var sub = strArg(conf, call, "sub", 1, "")
-  if len(sub) == 0: invalidPragma(conf, call)
+  if sub.len == 0: invalidPragma(conf, call)
   var by = strArg(conf, call, "by", 2, "")
   result = llStreamOpen("")
   var line = newStringOfCap(80)
diff --git a/compiler/forloops.nim b/compiler/forloops.nim
index 2cd1db7f7..d857b3c51 100644
--- a/compiler/forloops.nim
+++ b/compiler/forloops.nim
@@ -45,13 +45,13 @@ proc counterInTree(n, loop: PNode; counter: PSym): bool =
     for it in n:
       if counterInTree(it.lastSon): return true
   else:
-    for i in 0 ..< safeLen(n):
+    for i in 0..<n.safeLen:
       if counterInTree(n[i], loop, counter): return true
 
 proc copyExcept(n: PNode, x, dest: PNode) =
   if x == n: return
   if n.kind in {nkStmtList, nkStmtListExpr}:
-    for i in 0 ..< n.len: copyExcept(n[i], x, dest)
+    for i in 0..<n.len: copyExcept(n[i], x, dest)
   else:
     dest.add n
 
diff --git a/compiler/guards.nim b/compiler/guards.nim
index 8b7dc1d89..a2cbdbda2 100644
--- a/compiler/guards.nim
+++ b/compiler/guards.nim
@@ -65,16 +65,16 @@ proc isLetLocation(m: PNode, isApprox: bool): bool =
   while true:
     case n.kind
     of nkDotExpr, nkCheckedFieldExpr, nkObjUpConv, nkObjDownConv:
-      n = n.sons[0]
+      n = n[0]
     of nkDerefExpr, nkHiddenDeref:
-      n = n.sons[0]
+      n = n[0]
       inc derefs
     of nkBracketExpr:
-      if isConstExpr(n.sons[1]) or isLet(n.sons[1]) or isConstExpr(n.sons[1].skipConv):
-        n = n.sons[0]
+      if isConstExpr(n[1]) or isLet(n[1]) or isConstExpr(n[1].skipConv):
+        n = n[0]
       else: return
     of nkHiddenStdConv, nkHiddenSubConv, nkConv:
-      n = n.sons[1]
+      n = n[1]
     else:
       break
   result = n.isLet and derefs <= ord(isApprox)
@@ -105,34 +105,34 @@ proc initOperators*(g: ModuleGraph): Operators =
 
 proc swapArgs(fact: PNode, newOp: PSym): PNode =
   result = newNodeI(nkCall, fact.info, 3)
-  result.sons[0] = newSymNode(newOp)
-  result.sons[1] = fact.sons[2]
-  result.sons[2] = fact.sons[1]
+  result[0] = newSymNode(newOp)
+  result[1] = fact[2]
+  result[2] = fact[1]
 
 proc neg(n: PNode; o: Operators): PNode =
   if n == nil: return nil
   case n.getMagic
   of mNot:
-    result = n.sons[1]
+    result = n[1]
   of someLt:
     # not (a < b)  ==  a >= b  ==  b <= a
     result = swapArgs(n, o.opLe)
   of someLe:
     result = swapArgs(n, o.opLt)
   of mInSet:
-    if n.sons[1].kind != nkCurly: return nil
-    let t = n.sons[2].typ.skipTypes(abstractInst)
+    if n[1].kind != nkCurly: return nil
+    let t = n[2].typ.skipTypes(abstractInst)
     result = newNodeI(nkCall, n.info, 3)
-    result.sons[0] = n.sons[0]
-    result.sons[2] = n.sons[2]
+    result[0] = n[0]
+    result[2] = n[2]
     if t.kind == tyEnum:
-      var s = newNodeIT(nkCurly, n.info, n.sons[1].typ)
+      var s = newNodeIT(nkCurly, n.info, n[1].typ)
       for e in t.n:
         let eAsNode = newIntNode(nkIntLit, e.sym.position)
-        if not inSet(n.sons[1], eAsNode): s.add eAsNode
-      result.sons[1] = s
+        if not inSet(n[1], eAsNode): s.add eAsNode
+      result[1] = s
     #elif t.kind notin {tyString, tySequence} and lengthOrd(t) < 1000:
-    #  result.sons[1] = complement(n.sons[1])
+    #  result[1] = complement(n[1])
     else:
       # not ({2, 3, 4}.contains(x))   x != 2 and x != 3 and x != 4
       # XXX todo
@@ -140,13 +140,13 @@ proc neg(n: PNode; o: Operators): PNode =
   of mOr:
     # not (a or b) --> not a and not b
     let
-      a = n.sons[1].neg(o)
-      b = n.sons[2].neg(o)
+      a = n[1].neg(o)
+      b = n[2].neg(o)
     if a != nil and b != nil:
       result = newNodeI(nkCall, n.info, 3)
-      result.sons[0] = newSymNode(o.opAnd)
-      result.sons[1] = a
-      result.sons[2] = b
+      result[0] = newSymNode(o.opAnd)
+      result[1] = a
+      result[2] = b
     elif a != nil:
       result = a
     elif b != nil:
@@ -154,19 +154,19 @@ proc neg(n: PNode; o: Operators): PNode =
   else:
     # leave  not (a == 4)  as it is
     result = newNodeI(nkCall, n.info, 2)
-    result.sons[0] = newSymNode(o.opNot)
-    result.sons[1] = n
+    result[0] = newSymNode(o.opNot)
+    result[1] = n
 
 proc buildCall(op: PSym; a: PNode): PNode =
   result = newNodeI(nkCall, a.info, 2)
-  result.sons[0] = newSymNode(op)
-  result.sons[1] = a
+  result[0] = newSymNode(op)
+  result[1] = a
 
 proc buildCall(op: PSym; a, b: PNode): PNode =
   result = newNodeI(nkInfix, a.info, 3)
-  result.sons[0] = newSymNode(op)
-  result.sons[1] = a
-  result.sons[2] = b
+  result[0] = newSymNode(op)
+  result[1] = a
+  result[2] = b
 
 proc `|+|`(a, b: PNode): PNode =
   result = copyNode(a)
@@ -254,8 +254,8 @@ proc canon*(n: PNode; o: Operators): 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], o)
+    for i in 0..<n.len:
+      result[i] = canon(n[i], o)
   elif n.kind == nkSym and n.sym.kind == skLet and
       n.sym.astdef.getMagic in (someEq + someAdd + someMul + someMin +
       someMax + someHigh + {mUnaryLt} + someSub + someLen + someDiv):
@@ -265,8 +265,8 @@ proc canon*(n: PNode; o: Operators): PNode =
   case result.getMagic
   of someEq, someAdd, someMul, someMin, someMax:
     # these are symmetric; put value as last:
-    if result.sons[1].isValue and not result.sons[2].isValue:
-      result = swapArgs(result, result.sons[0].sym)
+    if result[1].isValue and not result[2].isValue:
+      result = swapArgs(result, result[0].sym)
       # (4 + foo) + 2 --> (foo + 4) + 2
   of someHigh:
     # high == len+(-1)
@@ -277,7 +277,7 @@ proc canon*(n: PNode; o: Operators): PNode =
     # x - 4  -->  x + (-4)
     result = negate(result[1], result[2], result, o)
   of someLen:
-    result.sons[0] = o.opLen.newSymNode
+    result[0] = o.opLen.newSymNode
   of someLt:
     # x < y  same as x <= y-1:
     let y = n[2].canon(o)
@@ -321,13 +321,13 @@ proc canon*(n: PNode; o: Operators): PNode =
     elif x.isValue and y.getMagic in someAdd and y[2].isValue:
       # 0 <= a.len + 3
       # -3 <= a.len
-      result.sons[1] = x |-| y[2]
-      result.sons[2] = y[1]
+      result[1] = x |-| y[2]
+      result[2] = y[1]
     elif x.isValue and y.getMagic in someSub and y[2].isValue:
       # 0 <= a.len - 3
       # 3 <= a.len
-      result.sons[1] = x |+| y[2]
-      result.sons[2] = y[1]
+      result[1] = x |+| y[2]
+      result[2] = y[1]
   else: discard
 
 proc buildAdd*(a: PNode; b: BiggestInt; o: Operators): PNode =
@@ -336,41 +336,41 @@ proc buildAdd*(a: PNode; b: BiggestInt; o: Operators): PNode =
 proc usefulFact(n: PNode; o: Operators): PNode =
   case n.getMagic
   of someEq:
-    if skipConv(n.sons[2]).kind == nkNilLit and (
-        isLetLocation(n.sons[1], false) or isVar(n.sons[1])):
-      result = o.opIsNil.buildCall(n.sons[1])
+    if skipConv(n[2]).kind == nkNilLit and (
+        isLetLocation(n[1], false) or isVar(n[1])):
+      result = o.opIsNil.buildCall(n[1])
     else:
-      if isLetLocation(n.sons[1], true) or isLetLocation(n.sons[2], true):
+      if isLetLocation(n[1], true) or isLetLocation(n[2], true):
         # XXX algebraic simplifications!  'i-1 < a.len' --> 'i < a.len+1'
         result = n
   of someLe+someLt:
-    if isLetLocation(n.sons[1], true) or isLetLocation(n.sons[2], true):
+    if isLetLocation(n[1], true) or isLetLocation(n[2], true):
       # XXX algebraic simplifications!  'i-1 < a.len' --> 'i < a.len+1'
       result = n
     elif n[1].getMagic in someLen or n[2].getMagic in someLen:
       # XXX Rethink this whole idea of 'usefulFact' for semparallel
       result = n
   of mIsNil:
-    if isLetLocation(n.sons[1], false) or isVar(n.sons[1]):
+    if isLetLocation(n[1], false) or isVar(n[1]):
       result = n
   of someIn:
-    if isLetLocation(n.sons[1], true):
+    if isLetLocation(n[1], true):
       result = n
   of mAnd:
     let
-      a = usefulFact(n.sons[1], o)
-      b = usefulFact(n.sons[2], o)
+      a = usefulFact(n[1], o)
+      b = usefulFact(n[2], o)
     if a != nil and b != nil:
       result = newNodeI(nkCall, n.info, 3)
-      result.sons[0] = newSymNode(o.opAnd)
-      result.sons[1] = a
-      result.sons[2] = b
+      result[0] = newSymNode(o.opAnd)
+      result[1] = a
+      result[2] = b
     elif a != nil:
       result = a
     elif b != nil:
       result = b
   of mNot:
-    let a = usefulFact(n.sons[1], o)
+    let a = usefulFact(n[1], o)
     if a != nil:
       result = a.neg(o)
   of mOr:
@@ -381,13 +381,13 @@ proc usefulFact(n: PNode; o: Operators): PNode =
     #  (x == 3) or (y == 2)  ---> not ( not (x==3) and not (y == 2))
     #  not (x != 3 and y != 2)
     let
-      a = usefulFact(n.sons[1], o).neg(o)
-      b = usefulFact(n.sons[2], o).neg(o)
+      a = usefulFact(n[1], o).neg(o)
+      b = usefulFact(n[2], o).neg(o)
     if a != nil and b != nil:
       result = newNodeI(nkCall, n.info, 3)
-      result.sons[0] = newSymNode(o.opAnd)
-      result.sons[1] = a
-      result.sons[2] = b
+      result[0] = newSymNode(o.opAnd)
+      result[1] = a
+      result[2] = b
       result = result.neg(o)
   elif n.kind == nkSym and n.sym.kind == skLet:
     # consider:
@@ -442,16 +442,16 @@ proc sameTree*(a, b: PNode): bool =
     of nkType: result = a.typ == b.typ
     of nkEmpty, nkNilLit: result = true
     else:
-      if len(a) == len(b):
-        for i in 0 ..< len(a):
-          if not sameTree(a.sons[i], b.sons[i]): return
+      if a.len == b.len:
+        for i in 0..<a.len:
+          if not sameTree(a[i], b[i]): return
         result = true
 
 proc hasSubTree(n, x: PNode): bool =
   if n.sameTree(x): result = true
   else:
-    for i in 0..safeLen(n)-1:
-      if hasSubTree(n.sons[i], x): return true
+    for i in 0..n.safeLen-1:
+      if hasSubTree(n[i], x): return true
 
 proc invalidateFacts*(m: var TModel, n: PNode) =
   # We are able to guard local vars (as opposed to 'let' variables)!
@@ -479,21 +479,21 @@ proc valuesUnequal(a, b: PNode): bool =
     result = not sameValue(a, b)
 
 proc impliesEq(fact, eq: PNode): TImplication =
-  let (loc, val) = if isLocation(eq.sons[1]): (1, 2) else: (2, 1)
+  let (loc, val) = if isLocation(eq[1]): (1, 2) else: (2, 1)
 
-  case fact.sons[0].sym.magic
+  case fact[0].sym.magic
   of someEq:
-    if sameTree(fact.sons[1], eq.sons[loc]):
+    if sameTree(fact[1], eq[loc]):
       # this is not correct; consider:  a == b;  a == 1 --> unknown!
-      if sameTree(fact.sons[2], eq.sons[val]): result = impYes
-      elif valuesUnequal(fact.sons[2], eq.sons[val]): result = impNo
-    elif sameTree(fact.sons[2], eq.sons[loc]):
-      if sameTree(fact.sons[1], eq.sons[val]): result = impYes
-      elif valuesUnequal(fact.sons[1], eq.sons[val]): result = impNo
+      if sameTree(fact[2], eq[val]): result = impYes
+      elif valuesUnequal(fact[2], eq[val]): result = impNo
+    elif sameTree(fact[2], eq[loc]):
+      if sameTree(fact[1], eq[val]): result = impYes
+      elif valuesUnequal(fact[1], eq[val]): result = impNo
   of mInSet:
     # remember: mInSet is 'contains' so the set comes first!
-    if sameTree(fact.sons[2], eq.sons[loc]) and isValue(eq.sons[val]):
-      if inSet(fact.sons[1], eq.sons[val]): result = impYes
+    if sameTree(fact[2], eq[loc]) and isValue(eq[val]):
+      if inSet(fact[1], eq[val]): result = impYes
       else: result = impNo
   of mNot, mOr, mAnd: assert(false, "impliesEq")
   else: discard
@@ -536,28 +536,28 @@ proc compareSets(a, b: PNode): TImplication =
   elif intersectSets(nil, a, b).len == 0: result = impNo
 
 proc impliesIn(fact, loc, aSet: PNode): TImplication =
-  case fact.sons[0].sym.magic
+  case fact[0].sym.magic
   of someEq:
-    if sameTree(fact.sons[1], loc):
-      if inSet(aSet, fact.sons[2]): result = impYes
+    if sameTree(fact[1], loc):
+      if inSet(aSet, fact[2]): result = impYes
       else: result = impNo
-    elif sameTree(fact.sons[2], loc):
-      if inSet(aSet, fact.sons[1]): result = impYes
+    elif sameTree(fact[2], loc):
+      if inSet(aSet, fact[1]): result = impYes
       else: result = impNo
   of mInSet:
-    if sameTree(fact.sons[2], loc):
-      result = compareSets(fact.sons[1], aSet)
+    if sameTree(fact[2], loc):
+      result = compareSets(fact[1], aSet)
   of someLe:
-    if sameTree(fact.sons[1], loc):
-      result = leImpliesIn(fact.sons[1], fact.sons[2], aSet)
-    elif sameTree(fact.sons[2], loc):
-      result = geImpliesIn(fact.sons[2], fact.sons[1], aSet)
+    if sameTree(fact[1], loc):
+      result = leImpliesIn(fact[1], fact[2], aSet)
+    elif sameTree(fact[2], loc):
+      result = geImpliesIn(fact[2], fact[1], aSet)
   of someLt:
-    if sameTree(fact.sons[1], loc):
-      result = leImpliesIn(fact.sons[1], fact.sons[2].pred, aSet)
-    elif sameTree(fact.sons[2], loc):
+    if sameTree(fact[1], loc):
+      result = leImpliesIn(fact[1], fact[2].pred, aSet)
+    elif sameTree(fact[2], loc):
       # 4 < x  -->  3 <= x
-      result = geImpliesIn(fact.sons[2], fact.sons[1].pred, aSet)
+      result = geImpliesIn(fact[2], fact[1].pred, aSet)
   of mNot, mOr, mAnd: assert(false, "impliesIn")
   else: discard
 
@@ -567,90 +567,90 @@ proc valueIsNil(n: PNode): TImplication =
   else: impUnknown
 
 proc impliesIsNil(fact, eq: PNode): TImplication =
-  case fact.sons[0].sym.magic
+  case fact[0].sym.magic
   of mIsNil:
-    if sameTree(fact.sons[1], eq.sons[1]):
+    if sameTree(fact[1], eq[1]):
       result = impYes
   of someEq:
-    if sameTree(fact.sons[1], eq.sons[1]):
-      result = valueIsNil(fact.sons[2].skipConv)
-    elif sameTree(fact.sons[2], eq.sons[1]):
-      result = valueIsNil(fact.sons[1].skipConv)
+    if sameTree(fact[1], eq[1]):
+      result = valueIsNil(fact[2].skipConv)
+    elif sameTree(fact[2], eq[1]):
+      result = valueIsNil(fact[1].skipConv)
   of mNot, mOr, mAnd: assert(false, "impliesIsNil")
   else: discard
 
 proc impliesGe(fact, x, c: PNode): TImplication =
   assert isLocation(x)
-  case fact.sons[0].sym.magic
+  case fact[0].sym.magic
   of someEq:
-    if sameTree(fact.sons[1], x):
-      if isValue(fact.sons[2]) and isValue(c):
+    if sameTree(fact[1], x):
+      if isValue(fact[2]) and isValue(c):
         # fact:  x = 4;  question x >= 56? --> true iff 4 >= 56
-        if leValue(c, fact.sons[2]): result = impYes
+        if leValue(c, fact[2]): result = impYes
         else: result = impNo
-    elif sameTree(fact.sons[2], x):
-      if isValue(fact.sons[1]) and isValue(c):
-        if leValue(c, fact.sons[1]): result = impYes
+    elif sameTree(fact[2], x):
+      if isValue(fact[1]) and isValue(c):
+        if leValue(c, fact[1]): result = impYes
         else: result = impNo
   of someLt:
-    if sameTree(fact.sons[1], x):
-      if isValue(fact.sons[2]) and isValue(c):
+    if sameTree(fact[1], x):
+      if isValue(fact[2]) and isValue(c):
         # fact:  x < 4;  question N <= x? --> false iff N <= 4
-        if leValue(fact.sons[2], c): result = impNo
+        if leValue(fact[2], c): result = impNo
         # fact:  x < 4;  question 2 <= x? --> we don't know
-    elif sameTree(fact.sons[2], x):
+    elif sameTree(fact[2], x):
       # fact: 3 < x; question: N-1 < x ?  --> true iff N-1 <= 3
-      if isValue(fact.sons[1]) and isValue(c):
-        if leValue(c.pred, fact.sons[1]): result = impYes
+      if isValue(fact[1]) and isValue(c):
+        if leValue(c.pred, fact[1]): result = impYes
   of someLe:
-    if sameTree(fact.sons[1], x):
-      if isValue(fact.sons[2]) and isValue(c):
+    if sameTree(fact[1], x):
+      if isValue(fact[2]) and isValue(c):
         # fact:  x <= 4;  question x >= 56? --> false iff 4 <= 56
-        if leValue(fact.sons[2], c): result = impNo
+        if leValue(fact[2], c): result = impNo
         # fact:  x <= 4;  question x >= 2? --> we don't know
-    elif sameTree(fact.sons[2], x):
+    elif sameTree(fact[2], x):
       # fact: 3 <= x; question: x >= 2 ?  --> true iff 2 <= 3
-      if isValue(fact.sons[1]) and isValue(c):
-        if leValue(c, fact.sons[1]): result = impYes
+      if isValue(fact[1]) and isValue(c):
+        if leValue(c, fact[1]): result = impYes
   of mNot, mOr, mAnd: assert(false, "impliesGe")
   else: discard
 
 proc impliesLe(fact, x, c: PNode): TImplication =
   if not isLocation(x):
     return impliesGe(fact, c, x)
-  case fact.sons[0].sym.magic
+  case fact[0].sym.magic
   of someEq:
-    if sameTree(fact.sons[1], x):
-      if isValue(fact.sons[2]) and isValue(c):
+    if sameTree(fact[1], x):
+      if isValue(fact[2]) and isValue(c):
         # fact:  x = 4;  question x <= 56? --> true iff 4 <= 56
-        if leValue(fact.sons[2], c): result = impYes
+        if leValue(fact[2], c): result = impYes
         else: result = impNo
-    elif sameTree(fact.sons[2], x):
-      if isValue(fact.sons[1]) and isValue(c):
-        if leValue(fact.sons[1], c): result = impYes
+    elif sameTree(fact[2], x):
+      if isValue(fact[1]) and isValue(c):
+        if leValue(fact[1], c): result = impYes
         else: result = impNo
   of someLt:
-    if sameTree(fact.sons[1], x):
-      if isValue(fact.sons[2]) and isValue(c):
+    if sameTree(fact[1], x):
+      if isValue(fact[2]) and isValue(c):
         # fact:  x < 4;  question x <= N? --> true iff N-1 <= 4
-        if leValue(fact.sons[2], c.pred): result = impYes
+        if leValue(fact[2], c.pred): result = impYes
         # fact:  x < 4;  question x <= 2? --> we don't know
-    elif sameTree(fact.sons[2], x):
+    elif sameTree(fact[2], x):
       # fact: 3 < x; question: x <= 1 ?  --> false iff 1 <= 3
-      if isValue(fact.sons[1]) and isValue(c):
-        if leValue(c, fact.sons[1]): result = impNo
+      if isValue(fact[1]) and isValue(c):
+        if leValue(c, fact[1]): result = impNo
 
   of someLe:
-    if sameTree(fact.sons[1], x):
-      if isValue(fact.sons[2]) and isValue(c):
+    if sameTree(fact[1], x):
+      if isValue(fact[2]) and isValue(c):
         # fact:  x <= 4;  question x <= 56? --> true iff 4 <= 56
-        if leValue(fact.sons[2], c): result = impYes
+        if leValue(fact[2], c): result = impYes
         # fact:  x <= 4;  question x <= 2? --> we don't know
 
-    elif sameTree(fact.sons[2], x):
+    elif sameTree(fact[2], x):
       # fact: 3 <= x; question: x <= 2 ?  --> false iff 2 < 3
-      if isValue(fact.sons[1]) and isValue(c):
-        if leValue(c, fact.sons[1].pred): result = impNo
+      if isValue(fact[1]) and isValue(c):
+        if leValue(c, fact[1].pred): result = impNo
 
   of mNot, mOr, mAnd: assert(false, "impliesLe")
   else: discard
@@ -686,32 +686,32 @@ proc factImplies(fact, prop: PNode): TImplication =
 
     #  (not a) -> b  compute as  not (a -> b) ???
     #  == not a or not b == not (a and b)
-    let arg = fact.sons[1]
+    let arg = fact[1]
     case arg.getMagic
     of mIsNil, mEqRef:
       return ~factImplies(arg, prop)
     of mAnd:
       # not (a and b)  means  not a or not b:
       # a or b --> both need to imply 'prop'
-      let a = factImplies(arg.sons[1], prop)
-      let b = factImplies(arg.sons[2], prop)
+      let a = factImplies(arg[1], prop)
+      let b = factImplies(arg[2], prop)
       if a == b: return ~a
       return impUnknown
     else:
       return impUnknown
   of mAnd:
-    result = factImplies(fact.sons[1], prop)
+    result = factImplies(fact[1], prop)
     if result != impUnknown: return result
-    return factImplies(fact.sons[2], prop)
+    return factImplies(fact[2], prop)
   else: discard
 
-  case prop.sons[0].sym.magic
-  of mNot: result = ~fact.factImplies(prop.sons[1])
+  case prop[0].sym.magic
+  of mNot: result = ~fact.factImplies(prop[1])
   of mIsNil: result = impliesIsNil(fact, prop)
   of someEq: result = impliesEq(fact, prop)
-  of someLe: result = impliesLe(fact, prop.sons[1], prop.sons[2])
-  of someLt: result = impliesLt(fact, prop.sons[1], prop.sons[2])
-  of mInSet: result = impliesIn(fact, prop.sons[2], prop.sons[1])
+  of someLe: result = impliesLe(fact, prop[1], prop[2])
+  of someLt: result = impliesLt(fact, prop[1], prop[2])
+  of mInSet: result = impliesIn(fact, prop[2], prop[1])
   else: result = impUnknown
 
 proc doesImply*(facts: TModel, prop: PNode): TImplication =
@@ -881,8 +881,8 @@ proc replaceSubTree(n, x, by: PNode): PNode =
     result = by
   elif hasSubTree(n, x):
     result = shallowCopy(n)
-    for i in 0 .. safeLen(n)-1:
-      result.sons[i] = replaceSubTree(n.sons[i], x, by)
+    for i in 0..n.safeLen-1:
+      result[i] = replaceSubTree(n[i], x, by)
   else:
     result = n
 
@@ -971,37 +971,37 @@ proc settype(n: PNode): PType =
 proc buildOf(it, loc: PNode; o: Operators): PNode =
   var s = newNodeI(nkCurly, it.info, it.len-1)
   s.typ = settype(loc)
-  for i in 0..it.len-2: s.sons[i] = it.sons[i]
+  for i in 0..<it.len-1: s[i] = it[i]
   result = newNodeI(nkCall, it.info, 3)
-  result.sons[0] = newSymNode(o.opContains)
-  result.sons[1] = s
-  result.sons[2] = loc
+  result[0] = newSymNode(o.opContains)
+  result[1] = s
+  result[2] = loc
 
 proc buildElse(n: PNode; o: Operators): PNode =
-  var s = newNodeIT(nkCurly, n.info, settype(n.sons[0]))
-  for i in 1..n.len-2:
-    let branch = n.sons[i]
+  var s = newNodeIT(nkCurly, n.info, settype(n[0]))
+  for i in 1..<n.len-1:
+    let branch = n[i]
     assert branch.kind != nkElse
     if branch.kind == nkOfBranch:
-      for j in 0..branch.len-2:
-        s.add(branch.sons[j])
+      for j in 0..<branch.len-1:
+        s.add(branch[j])
   result = newNodeI(nkCall, n.info, 3)
-  result.sons[0] = newSymNode(o.opContains)
-  result.sons[1] = s
-  result.sons[2] = n.sons[0]
+  result[0] = newSymNode(o.opContains)
+  result[1] = s
+  result[2] = n[0]
 
 proc addDiscriminantFact*(m: var TModel, n: PNode) =
   var fact = newNodeI(nkCall, n.info, 3)
-  fact.sons[0] = newSymNode(m.o.opEq)
-  fact.sons[1] = n.sons[0]
-  fact.sons[2] = n.sons[1]
+  fact[0] = newSymNode(m.o.opEq)
+  fact[1] = n[0]
+  fact[2] = n[1]
   m.s.add fact
 
 proc addAsgnFact*(m: var TModel, key, value: PNode) =
   var fact = newNodeI(nkCall, key.info, 3)
-  fact.sons[0] = newSymNode(m.o.opEq)
-  fact.sons[1] = key
-  fact.sons[2] = value
+  fact[0] = newSymNode(m.o.opEq)
+  fact[1] = key
+  fact[2] = value
   m.s.add fact
 
 proc sameSubexprs*(m: TModel; a, b: PNode): bool =
@@ -1015,34 +1015,34 @@ proc sameSubexprs*(m: TModel; a, b: PNode): bool =
   # However, nil checking requires exactly the same mechanism! But for now
   # we simply use sameTree and live with the unsoundness of the analysis.
   var check = newNodeI(nkCall, a.info, 3)
-  check.sons[0] = newSymNode(m.o.opEq)
-  check.sons[1] = a
-  check.sons[2] = b
+  check[0] = newSymNode(m.o.opEq)
+  check[1] = a
+  check[2] = b
   result = m.doesImply(check) == impYes
 
 proc addCaseBranchFacts*(m: var TModel, n: PNode, i: int) =
-  let branch = n.sons[i]
+  let branch = n[i]
   if branch.kind == nkOfBranch:
-    m.s.add buildOf(branch, n.sons[0], m.o)
+    m.s.add buildOf(branch, n[0], m.o)
   else:
     m.s.add n.buildElse(m.o).neg(m.o)
 
 proc buildProperFieldCheck(access, check: PNode; o: Operators): PNode =
-  if check.sons[1].kind == nkCurly:
+  if check[1].kind == nkCurly:
     result = copyTree(check)
     if access.kind == nkDotExpr:
       var a = copyTree(access)
-      a.sons[1] = check.sons[2]
-      result.sons[2] = a
+      a[1] = check[2]
+      result[2] = a
       # 'access.kind != nkDotExpr' can happen for object constructors
       # which we don't check yet
   else:
     # it is some 'not'
     assert check.getMagic == mNot
-    result = buildProperFieldCheck(access, check.sons[1], o).neg(o)
+    result = buildProperFieldCheck(access, check[1], o).neg(o)
 
 proc checkFieldAccess*(m: TModel, n: PNode; conf: ConfigRef) =
-  for i in 1..n.len-1:
-    let check = buildProperFieldCheck(n.sons[0], n.sons[i], m.o)
+  for i in 1..<n.len:
+    let check = buildProperFieldCheck(n[0], n[i], m.o)
     if check != nil and m.doesImply(check) != impYes:
-      message(conf, n.info, warnProveField, renderTree(n.sons[0])); break
+      message(conf, n.info, warnProveField, renderTree(n[0])); break
diff --git a/compiler/hlo.nim b/compiler/hlo.nim
index 3ff2dd410..6756bdc2a 100644
--- a/compiler/hlo.nim
+++ b/compiler/hlo.nim
@@ -12,14 +12,14 @@
 proc hlo(c: PContext, n: PNode): PNode
 
 proc evalPattern(c: PContext, n, orig: PNode): PNode =
-  internalAssert c.config, n.kind == nkCall and n.sons[0].kind == nkSym
+  internalAssert c.config, n.kind == nkCall and n[0].kind == nkSym
   # we need to ensure that the resulting AST is semchecked. However, it's
   # awful to semcheck before macro invocation, so we don't and treat
   # templates and macros as immediate in this context.
   var rule: string
   if optHints in c.config.options and hintPattern in c.config.notes:
     rule = renderTree(n, {renderNoComments})
-  let s = n.sons[0].sym
+  let s = n[0].sym
   case s.kind
   of skMacro:
     result = semMacroExpr(c, n, orig, s)
@@ -50,7 +50,7 @@ proc applyPatterns(c: PContext, n: PNode): PNode =
         c.patterns[i] = nil
         if x.kind == nkStmtList:
           assert x.len == 3
-          x.sons[1] = evalPattern(c, x.sons[1], result)
+          x[1] = evalPattern(c, x[1], result)
           result = flattenStmts(x)
         else:
           result = evalPattern(c, x, result)
@@ -68,17 +68,17 @@ proc hlo(c: PContext, n: PNode): PNode =
     result = n
   else:
     if n.kind in {nkFastAsgn, nkAsgn, nkIdentDefs, nkVarTuple} and
-        n.sons[0].kind == nkSym and
-        {sfGlobal, sfPure} * n.sons[0].sym.flags == {sfGlobal, sfPure}:
+        n[0].kind == nkSym and
+        {sfGlobal, sfPure} * n[0].sym.flags == {sfGlobal, sfPure}:
       # do not optimize 'var g {.global} = re(...)' again!
       return n
     result = applyPatterns(c, n)
     if result == n:
       # no optimization applied, try subtrees:
-      for i in 0 ..< safeLen(result):
-        let a = result.sons[i]
+      for i in 0..<result.safeLen:
+        let a = result[i]
         let h = hlo(c, a)
-        if h != a: result.sons[i] = h
+        if h != a: result[i] = h
     else:
       # perform type checking, so that the replacement still fits:
       if isEmptyType(n.typ) and isEmptyType(result.typ):
diff --git a/compiler/idents.nim b/compiler/idents.nim
index 3153745d5..a035974f3 100644
--- a/compiler/idents.nim
+++ b/compiler/idents.nim
@@ -87,7 +87,7 @@ proc getIdent*(ic: IdentCache; identifier: cstring, length: int, h: Hash): PIden
   new(result)
   result.h = h
   result.s = newString(length)
-  for i in 0 ..< length: result.s[i] = identifier[i]
+  for i in 0..<length: result.s[i] = identifier[i]
   result.next = ic.buckets[idx]
   ic.buckets[idx] = result
   if id == 0:
@@ -97,11 +97,11 @@ proc getIdent*(ic: IdentCache; identifier: cstring, length: int, h: Hash): PIden
     result.id = id
 
 proc getIdent*(ic: IdentCache; identifier: string): PIdent =
-  result = getIdent(ic, cstring(identifier), len(identifier),
+  result = getIdent(ic, cstring(identifier), identifier.len,
                     hashIgnoreStyle(identifier))
 
 proc getIdent*(ic: IdentCache; identifier: string, h: Hash): PIdent =
-  result = getIdent(ic, cstring(identifier), len(identifier), h)
+  result = getIdent(ic, cstring(identifier), identifier.len, h)
 
 proc newIdentCache*(): IdentCache =
   result = IdentCache()
@@ -110,7 +110,7 @@ proc newIdentCache*(): IdentCache =
   result.idDelegator = result.getIdent":delegator"
   result.emptyIdent = result.getIdent("")
   # initialize the keywords:
-  for s in succ(low(specialWords)) .. high(specialWords):
+  for s in succ(low(specialWords))..high(specialWords):
     result.getIdent(specialWords[s], hashIgnoreStyle(specialWords[s])).id = ord(s)
 
 proc whichKeyword*(id: PIdent): TSpecialWord =
diff --git a/compiler/importer.nim b/compiler/importer.nim
index 70bbcccc8..844cb1ad0 100644
--- a/compiler/importer.nim
+++ b/compiler/importer.nim
@@ -16,7 +16,7 @@ import
 proc readExceptSet*(c: PContext, n: PNode): IntSet =
   assert n.kind in {nkImportExceptStmt, nkExportExceptStmt}
   result = initIntSet()
-  for i in 1 ..< n.len:
+  for i in 1..<n.len:
     let ident = lookups.considerQuotedIdent(c, n[i])
     result.incl(ident.id)
 
@@ -47,8 +47,8 @@ proc rawImportSymbol(c: PContext, s, origin: PSym) =
   if s.kind == skType:
     var etyp = s.typ
     if etyp.kind in {tyBool, tyEnum}:
-      for j in 0 ..< len(etyp.n):
-        var e = etyp.n.sons[j].sym
+      for j in 0..<etyp.n.len:
+        var e = etyp.n[j].sym
         if e.kind != skEnumField:
           internalError(c.config, s.info, "rawImportSymbol")
           # BUGFIX: because of aliases for enums the symbol may already
@@ -125,18 +125,18 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym) =
   of nkExportExceptStmt:
     localError(c.config, n.info, "'export except' not implemented")
   else:
-    for i in 0..safeLen(n)-1:
-      importForwarded(c, n.sons[i], exceptSet, fromMod)
+    for i in 0..n.safeLen-1:
+      importForwarded(c, n[i], exceptSet, fromMod)
 
 proc importModuleAs(c: PContext; n: PNode, realModule: PSym): PSym =
   result = realModule
   c.unusedImports.add((realModule, n.info))
   if n.kind != nkImportAs: discard
-  elif n.len != 2 or n.sons[1].kind != nkIdent:
+  elif n.len != 2 or n[1].kind != nkIdent:
     localError(c.config, n.info, "module alias must be an identifier")
-  elif n.sons[1].ident.id != realModule.name.id:
+  elif n[1].ident.id != realModule.name.id:
     # some misguided guy will write 'import abc.foo as foo' ...
-    result = createModuleAlias(realModule, n.sons[1].ident, realModule.info,
+    result = createModuleAlias(realModule, n[1].ident, realModule.info,
                                c.config.options)
 
 proc myImportModule(c: PContext, n: PNode; importStmtResult: PNode): PSym =
@@ -148,7 +148,7 @@ proc myImportModule(c: PContext, n: PNode; importStmtResult: PNode): PSym =
     #echo "adding ", toFullPath(f), " at ", L+1
     if recursion >= 0:
       var err = ""
-      for i in recursion ..< L:
+      for i in recursion..<L:
         if i > recursion: err.add "\n"
         err.add toFullPath(c.config, c.graph.importStack[i]) & " imports " &
                 toFullPath(c.config, c.graph.importStack[i+1])
@@ -178,8 +178,8 @@ proc myImportModule(c: PContext, n: PNode; importStmtResult: PNode): PSym =
 proc transformImportAs(c: PContext; n: PNode): PNode =
   if n.kind == nkInfix and considerQuotedIdent(c, n[0]).s == "as":
     result = newNodeI(nkImportAs, n.info)
-    result.add n.sons[1]
-    result.add n.sons[2]
+    result.add n[1]
+    result.add n[2]
   else:
     result = n
 
@@ -195,8 +195,8 @@ proc impMod(c: PContext; it: PNode; importStmtResult: PNode) =
 
 proc evalImport*(c: PContext, n: PNode): PNode =
   result = newNodeI(nkImportStmt, n.info)
-  for i in 0 ..< len(n):
-    let it = n.sons[i]
+  for i in 0..<n.len:
+    let it = n[i]
     if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket:
       let sep = it[0]
       let dir = it[1]
@@ -206,13 +206,13 @@ proc evalImport*(c: PContext, n: PNode): PNode =
       imp.add sep # dummy entry, replaced in the loop
       for x in it[2]:
         # transform `a/b/[c as d]` to `/a/b/c as d`
-        if x.kind == nkInfix and x.sons[0].ident.s == "as":
+        if x.kind == nkInfix and x[0].ident.s == "as":
           let impAs = copyTree(x)
-          imp.sons[2] = x.sons[1]
-          impAs.sons[1] = imp
+          imp[2] = x[1]
+          impAs[1] = imp
           impMod(c, imp, result)
         else:
-          imp.sons[2] = x
+          imp[2] = x
           impMod(c, imp, result)
     else:
       impMod(c, it, result)
@@ -220,22 +220,22 @@ proc evalImport*(c: PContext, n: PNode): PNode =
 proc evalFrom*(c: PContext, n: PNode): PNode =
   result = newNodeI(nkImportStmt, n.info)
   checkMinSonsLen(n, 2, c.config)
-  n.sons[0] = transformImportAs(c, n.sons[0])
-  var m = myImportModule(c, n.sons[0], result)
+  n[0] = transformImportAs(c, n[0])
+  var m = myImportModule(c, n[0], result)
   if m != nil:
-    n.sons[0] = newSymNode(m)
+    n[0] = newSymNode(m)
     addDecl(c, m, n.info)               # add symbol to symbol table of module
-    for i in 1 ..< len(n):
-      if n.sons[i].kind != nkNilLit:
-        importSymbol(c, n.sons[i], m)
+    for i in 1..<n.len:
+      if n[i].kind != nkNilLit:
+        importSymbol(c, n[i], m)
 
 proc evalImportExcept*(c: PContext, n: PNode): PNode =
   result = newNodeI(nkImportStmt, n.info)
   checkMinSonsLen(n, 2, c.config)
-  n.sons[0] = transformImportAs(c, n.sons[0])
-  var m = myImportModule(c, n.sons[0], result)
+  n[0] = transformImportAs(c, n[0])
+  var m = myImportModule(c, n[0], result)
   if m != nil:
-    n.sons[0] = newSymNode(m)
+    n[0] = newSymNode(m)
     addDecl(c, m, n.info)               # add symbol to symbol table of module
     importAllSymbolsExcept(c, m, readExceptSet(c, n))
     #importForwarded(c, m.ast, exceptSet, m)
diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim
index 705d8c3e8..8c7170577 100644
--- a/compiler/injectdestructors.nim
+++ b/compiler/injectdestructors.nim
@@ -259,7 +259,7 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode =
   vpart[0] = tempAsNode
   vpart[1] = c.emptyNode
   vpart[2] = n
-  add(v, vpart)
+  v.add(vpart)
 
   result.add v
   result.add genWasMoved(skipConv(n), c)
@@ -685,7 +685,7 @@ proc injectDefaultCalls(n: PNode, c: var Con) =
       nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef:
     discard
   else:
-    for i in 0..<safeLen(n):
+    for i in 0..<n.safeLen:
       injectDefaultCalls(n[i], c)
 
 proc extractDestroysForTemporaries(c: Con, destroys: PNode): PNode =
diff --git a/compiler/int128.nim b/compiler/int128.nim
index 23079569a..dcfdc7b4b 100644
--- a/compiler/int128.nim
+++ b/compiler/int128.nim
@@ -162,7 +162,7 @@ proc castToUInt64*(arg: Int128): uint64 =
   cast[uint64](bitconcat(arg.udata[1], arg.udata[0]))
 
 proc addToHex(result: var string; arg: uint32) =
-  for i in 0 ..< 8:
+  for i in 0..<8:
     let idx = (arg shr ((7-i) * 4)) and 0xf
     result.add "0123456789abcdef"[idx]
 
@@ -430,7 +430,7 @@ proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] =
 
   # Uses shift-subtract algorithm to divide dividend by denominator. The
   # remainder will be left in dividend.
-  for i in 0 .. shift:
+  for i in 0..shift:
     quotient = quotient shl 1
     if dividend >= denominator:
       dividend = dividend - denominator
@@ -492,7 +492,7 @@ proc parseDecimalInt128*(arg: string, pos: int = 0): Int128 =
     pos += 1
 
   result = Zero
-  while pos < arg.len and arg[pos] in '0' .. '9':
+  while pos < arg.len and arg[pos] in '0'..'9':
     result = result * Ten
     result.inc(uint32(arg[pos]) - uint32('0'))
     pos += 1
@@ -652,8 +652,8 @@ when isMainModule:
   d[37] = parseDecimalInt128("10000000000000000000000000000000000000")
   d[38] = parseDecimalInt128("100000000000000000000000000000000000000")
 
-  for i in 0 ..< d.len:
-    for j in 0 ..< d.len:
+  for i in 0..<d.len:
+    for j in 0..<d.len:
       doAssert(cmp(d[i], d[j]) == cmp(i,j))
       if i + j < d.len:
         doAssert d[i] * d[j] == d[i+j]
@@ -670,8 +670,8 @@ when isMainModule:
   for it in d.mitems:
     it = -it
 
-  for i in 0 ..< d.len:
-    for j in 0 ..< d.len:
+  for i in 0..<d.len:
+    for j in 0..<d.len:
       doAssert(cmp(d[i], d[j]) == -cmp(i,j))
       if i + j < d.len:
         doAssert d[i] * d[j] == -d[i+j]
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 76b8121bf..3f4b29238 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -109,20 +109,20 @@ proc indentLine(p: PProc, r: Rope): Rope =
   result = r
   var p = p
   while true:
-    for i in 0 ..< p.blocks.len + p.extraIndent:
+    for i in 0..<p.blocks.len + p.extraIndent:
       prepend(result, rope"  ")
     if p.up == nil or p.up.prc != p.prc.owner:
       break
     p = p.up
 
 template line(p: PProc, added: string) =
-  add(p.body, indentLine(p, rope(added)))
+  p.body.add(indentLine(p, rope(added)))
 
 template line(p: PProc, added: Rope) =
-  add(p.body, indentLine(p, added))
+  p.body.add(indentLine(p, added))
 
 template lineF(p: PProc, frmt: FormatStr, args: varargs[Rope]) =
-  add(p.body, indentLine(p, ropes.`%`(frmt, args)))
+  p.body.add(indentLine(p, ropes.`%`(frmt, args)))
 
 template nested(p, body) =
   inc p.extraIndent
@@ -157,7 +157,7 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
     procDef: procDef,
     g: globals,
     extraIndent: int(procDef != nil))
-  if procDef != nil: result.prc = procDef.sons[namePos].sym
+  if procDef != nil: result.prc = procDef[namePos].sym
 
 proc declareGlobal(p: PProc; id: int; r: Rope) =
   if p.prc != nil and not p.declaredGlobals.containsOrIncl(id):
@@ -179,7 +179,7 @@ proc mapType(typ: PType): TJSTypeKind =
     # treat a tyPointer like a typed pointer to an array of bytes
     result = etyBaseIndex
   of tyRange, tyDistinct, tyOrdinal, tyProxy:
-    result = mapType(t.sons[0])
+    result = mapType(t[0])
   of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: result = etyInt
   of tyBool: result = etyBool
   of tyFloat..tyFloat128: result = etyFloat
@@ -253,10 +253,10 @@ proc mangleName(m: BModule, s: PSym): Rope =
       if m.config.hcrOn:
         # When hot reloading is enabled, we must ensure that the names
         # of functions and types will be preserved across rebuilds:
-        add(result, idOrSig(s, m.module.name.s, m.sigConflicts))
+        result.add(idOrSig(s, m.module.name.s, m.sigConflicts))
       else:
-        add(result, "_")
-        add(result, rope(s.id))
+        result.add("_")
+        result.add(rope(s.id))
     s.loc.r = result
 
 proc escapeJSString(s: string): string =
@@ -273,7 +273,7 @@ proc escapeJSString(s: string): string =
     of '\v': result.add("\\v")
     of '\\': result.add("\\\\")
     of '\"': result.add("\\\"")
-    else: add(result, c)
+    else: result.add(c)
   result.add("\"")
 
 proc makeJSString(s: string, escapeNonAscii = true): Rope =
@@ -296,7 +296,7 @@ proc useMagic(p: PProc, name: string) =
     internalAssert p.config, s.kind in {skProc, skFunc, skMethod, skConverter}
     if not p.g.generatedSyms.containsOrIncl(s.id):
       let code = genProc(p, s)
-      add(p.g.constants, code)
+      p.g.constants.add(code)
   else:
     if p.prc != nil:
       globalError(p.config, p.prc.info, "system module needs: " & name)
@@ -317,7 +317,7 @@ proc getTemp(p: PProc, defineInLocals: bool = true): Rope =
   inc(p.unique)
   result = "Tmp$1" % [rope(p.unique)]
   if defineInLocals:
-    add(p.locals, p.indentLine("var $1;$n" % [result]))
+    p.locals.add(p.indentLine("var $1;$n" % [result]))
 
 proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
   assert r.kind == resNone
@@ -468,8 +468,8 @@ template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
   # lhs and rhs respectively
   var x, y: TCompRes
   useMagic(p, magic)
-  gen(p, n.sons[1], x)
-  gen(p, n.sons[2], y)
+  gen(p, n[1], x)
+  gen(p, n[2], y)
 
   var
     a, tmp = x.rdLoc
@@ -494,8 +494,8 @@ template unsignedTrimmer(size: BiggestInt): Rope =
 proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string,
                     reassign = false) =
   var x, y: TCompRes
-  gen(p, n.sons[1], x)
-  gen(p, n.sons[2], y)
+  gen(p, n[1], x)
+  gen(p, n[2], y)
   let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size)
   if reassign:
     let (a, tmp) = maybeMakeTemp(p, n[1], x)
@@ -507,16 +507,16 @@ proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string,
 template ternaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
   var x, y, z: TCompRes
   useMagic(p, magic)
-  gen(p, n.sons[1], x)
-  gen(p, n.sons[2], y)
-  gen(p, n.sons[3], z)
+  gen(p, n[1], x)
+  gen(p, n[2], y)
+  gen(p, n[3], z)
   r.res = frmt % [x.rdLoc, y.rdLoc, z.rdLoc]
   r.kind = resExpr
 
 template unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
   # $1 binds to n[1], if $2 is present it will be substituted to a tmp of $1
   useMagic(p, magic)
-  gen(p, n.sons[1], r)
+  gen(p, n[1], r)
   var a, tmp = r.rdLoc
   if "$2" in frmt: (a, tmp) = maybeMakeTemp(p, n[1], r)
   r.res = frmt % [a, tmp]
@@ -528,13 +528,13 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
     xLoc,yLoc: Rope
   let i = ord(optOverflowCheck notin p.options)
   useMagic(p, jsMagics[op][i])
-  if len(n) > 2:
-    gen(p, n.sons[1], x)
-    gen(p, n.sons[2], y)
+  if n.len > 2:
+    gen(p, n[1], x)
+    gen(p, n[2], y)
     xLoc = x.rdLoc
     yLoc = y.rdLoc
   else:
-    gen(p, n.sons[1], r)
+    gen(p, n[1], r)
     xLoc = r.rdLoc
 
   template applyFormat(frmtA, frmtB: string) =
@@ -624,8 +624,8 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
     arithAux(p, n, r, op)
   of mShrI:
     var x, y: TCompRes
-    gen(p, n.sons[1], x)
-    gen(p, n.sons[2], y)
+    gen(p, n[1], x)
+    gen(p, n[2], y)
     let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size)
     r.res = "(($1 $2) >>> $3)" % [x.rdLoc, trimmer, y.rdLoc]
   of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr,
@@ -656,23 +656,21 @@ proc genLineDir(p: PProc, n: PNode) =
     lineF(p, "F.line = $1;$n", [rope(line)])
 
 proc genWhileStmt(p: PProc, n: PNode) =
-  var
-    cond: TCompRes
+  var cond: TCompRes
   internalAssert p.config, isEmptyType(n.typ)
   genLineDir(p, n)
   inc(p.unique)
-  var length = len(p.blocks)
-  setLen(p.blocks, length + 1)
-  p.blocks[length].id = -p.unique
-  p.blocks[length].isLoop = true
+  setLen(p.blocks, p.blocks.len + 1)
+  p.blocks[^1].id = -p.unique
+  p.blocks[^1].isLoop = true
   let labl = p.unique.rope
   lineF(p, "L$1: while (true) {$n", [labl])
-  p.nested: gen(p, n.sons[0], cond)
+  p.nested: gen(p, n[0], cond)
   lineF(p, "if (!$1) break L$2;$n",
        [cond.res, labl])
-  p.nested: genStmt(p, n.sons[1])
+  p.nested: genStmt(p, n[1])
   lineF(p, "}$n", [labl])
-  setLen(p.blocks, length)
+  setLen(p.blocks, p.blocks.len - 1)
 
 proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
   if src.kind != resNone:
@@ -713,30 +711,28 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
     r.res = getTemp(p)
   inc(p.unique)
   var i = 1
-  var length = len(n)
-  var catchBranchesExist = length > 1 and n.sons[i].kind == nkExceptBranch
+  var catchBranchesExist = n.len > 1 and n[i].kind == nkExceptBranch
   if catchBranchesExist:
-    add(p.body, "++excHandler;\L")
+    p.body.add("++excHandler;\L")
   var tmpFramePtr = rope"F"
   if optStackTrace notin p.options:
     tmpFramePtr = p.getTemp(true)
     line(p, tmpFramePtr & " = framePtr;\L")
   lineF(p, "try {$n", [])
   var a: TCompRes
-  gen(p, n.sons[0], a)
+  gen(p, n[0], a)
   moveInto(p, a, r)
   var generalCatchBranchExists = false
   if catchBranchesExist:
-    addf(p.body, "--excHandler;$n} catch (EXC) {$n var prevJSError = lastJSError;$n" &
+    p.body.addf("--excHandler;$n} catch (EXC) {$n var prevJSError = lastJSError;$n" &
         " lastJSError = EXC;$n --excHandler;$n", [])
     line(p, "framePtr = $1;$n" % [tmpFramePtr])
-  while i < length and n.sons[i].kind == nkExceptBranch:
-    let blen = len(n.sons[i])
-    if blen == 1:
+  while i < n.len and n[i].kind == nkExceptBranch:
+    if n[i].len == 1:
       # general except section:
       generalCatchBranchExists = true
       if i > 1: lineF(p, "else {$n", [])
-      gen(p, n.sons[i].sons[0], a)
+      gen(p, n[i][0], a)
       moveInto(p, a, r)
       if i > 1: lineF(p, "}$n", [])
     else:
@@ -744,9 +740,9 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
       var excAlias: PNode = nil
 
       useMagic(p, "isObj")
-      for j in 0 .. blen - 2:
+      for j in 0..<n[i].len - 1:
         var throwObj: PNode
-        let it = n.sons[i].sons[j]
+        let it = n[i][j]
 
         if it.isInfixAs():
           throwObj = it[1]
@@ -759,15 +755,15 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
         else:
           internalError(p.config, n.info, "genTryStmt")
 
-        if orExpr != nil: add(orExpr, "||")
+        if orExpr != nil: orExpr.add("||")
         # Generate the correct type checking code depending on whether this is a
         # NIM-native or a JS-native exception
         # if isJsObject(throwObj.typ):
         if isImportedException(throwObj.typ, p.config):
-          addf(orExpr, "lastJSError instanceof $1",
+          orExpr.addf("lastJSError instanceof $1",
             [throwObj.typ.sym.loc.r])
         else:
-          addf(orExpr, "isObj(lastJSError.m_type, $1)",
+          orExpr.addf("isObj(lastJSError.m_type, $1)",
                [genTypeInfo(p, throwObj.typ)])
 
       if i > 1: line(p, "else ")
@@ -777,7 +773,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
       if excAlias != nil:
         excAlias.sym.loc.r = mangleName(p.module, excAlias.sym)
         lineF(p, "var $1 = lastJSError;$n", excAlias.sym.loc.r)
-      gen(p, n.sons[i].sons[blen - 1], a)
+      gen(p, n[i][^1], a)
       moveInto(p, a, r)
       lineF(p, "}$n", [])
     inc(i)
@@ -790,15 +786,15 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
     lineF(p, "lastJSError = prevJSError;$n")
   line(p, "} finally {\L")
   line(p, "framePtr = $1;$n" % [tmpFramePtr])
-  if i < length and n.sons[i].kind == nkFinally:
-    genStmt(p, n.sons[i].sons[0])
+  if i < n.len and n[i].kind == nkFinally:
+    genStmt(p, n[i][0])
   line(p, "}\L")
 
 proc genRaiseStmt(p: PProc, n: PNode) =
-  if n.sons[0].kind != nkEmpty:
+  if n[0].kind != nkEmpty:
     var a: TCompRes
-    gen(p, n.sons[0], a)
-    let typ = skipTypes(n.sons[0].typ, abstractPtrs)
+    gen(p, n[0], a)
+    let typ = skipTypes(n[0].typ, abstractPtrs)
     genLineDir(p, n)
     useMagic(p, "raiseException")
     lineF(p, "raiseException($1, $2);$n",
@@ -812,8 +808,8 @@ 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
+  gen(p, n[0], cond)
+  let stringSwitch = skipTypes(n[0].typ, abstractVar).kind == tyString
   if stringSwitch:
     useMagic(p, "toJSStr")
     lineF(p, "switch (toJSStr($1)) {$n", [cond.rdLoc])
@@ -822,15 +818,15 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
   if not isEmptyType(n.typ):
     r.kind = resVal
     r.res = getTemp(p)
-  for i in 1 ..< len(n):
-    let it = n.sons[i]
+  for i in 1..<n.len:
+    let it = n[i]
     case it.kind
     of nkOfBranch:
-      for j in 0 .. len(it) - 2:
-        let e = it.sons[j]
+      for j in 0..<it.len - 1:
+        let e = it[j]
         if e.kind == nkRange:
-          var v = copyNode(e.sons[0])
-          while v.intVal <= e.sons[1].intVal:
+          var v = copyNode(e[0])
+          while v.intVal <= e[1].intVal:
             gen(p, v, cond)
             lineF(p, "case $1:$n", [cond.rdLoc])
             inc(v.intVal)
@@ -850,7 +846,7 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
     of nkElse:
       lineF(p, "default: $n", [])
       p.nested:
-        gen(p, it.sons[0], stmt)
+        gen(p, it[0], stmt)
         moveInto(p, stmt, r)
         lineF(p, "break;$n", [])
     else: internalError(p.config, it.info, "jsgen.genCaseStmt")
@@ -858,33 +854,33 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
 
 proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
   inc(p.unique)
-  let idx = len(p.blocks)
-  if n.sons[0].kind != nkEmpty:
+  let idx = p.blocks.len
+  if n[0].kind != nkEmpty:
     # named block?
-    if (n.sons[0].kind != nkSym): internalError(p.config, n.info, "genBlock")
-    var sym = n.sons[0].sym
+    if (n[0].kind != nkSym): internalError(p.config, n.info, "genBlock")
+    var sym = n[0].sym
     sym.loc.k = locOther
     sym.position = idx+1
   let labl = p.unique
   lineF(p, "L$1: do {$n", [labl.rope])
   setLen(p.blocks, idx + 1)
   p.blocks[idx].id = - p.unique # negative because it isn't used yet
-  gen(p, n.sons[1], r)
+  gen(p, n[1], r)
   setLen(p.blocks, idx)
   lineF(p, "} while(false);$n", [labl.rope])
 
 proc genBreakStmt(p: PProc, n: PNode) =
   var idx: int
   genLineDir(p, n)
-  if n.sons[0].kind != nkEmpty:
+  if n[0].kind != nkEmpty:
     # named break?
-    assert(n.sons[0].kind == nkSym)
-    let sym = n.sons[0].sym
+    assert(n[0].kind == nkSym)
+    let sym = n[0].sym
     assert(sym.loc.k == locOther)
     idx = sym.position-1
   else:
     # an unnamed 'break' can only break a loop after 'transf' pass:
-    idx = len(p.blocks) - 1
+    idx = p.blocks.len - 1
     while idx >= 0 and not p.blocks[idx].isLoop: dec idx
     if idx < 0 or not p.blocks[idx].isLoop:
       internalError(p.config, n.info, "no loop to break")
@@ -894,7 +890,7 @@ proc genBreakStmt(p: PProc, n: PNode) =
 proc genAsmOrEmitStmt(p: PProc, n: PNode) =
   genLineDir(p, n)
   p.body.add p.indentLine(nil)
-  for i in 0 ..< len(n):
+  for i in 0..<n.len:
     let it = n[i]
     case it.kind
     of nkStrLit..nkTripleStrLit:
@@ -932,41 +928,41 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) =
   if not isEmptyType(n.typ):
     r.kind = resVal
     r.res = getTemp(p)
-  for i in 0 ..< len(n):
-    let it = n.sons[i]
-    if len(it) != 1:
+  for i in 0..<n.len:
+    let it = n[i]
+    if it.len != 1:
       if i > 0:
         lineF(p, "else {$n", [])
         inc(toClose)
-      p.nested: gen(p, it.sons[0], cond)
+      p.nested: gen(p, it[0], cond)
       lineF(p, "if ($1) {$n", [cond.rdLoc])
-      gen(p, it.sons[1], stmt)
+      gen(p, it[1], stmt)
     else:
       # else part:
       lineF(p, "else {$n", [])
-      p.nested: gen(p, it.sons[0], stmt)
+      p.nested: gen(p, it[0], stmt)
     moveInto(p, stmt, r)
     lineF(p, "}$n", [])
   line(p, repeat('}', toClose) & "\L")
 
 proc generateHeader(p: PProc, typ: PType): Rope =
   result = nil
-  for i in 1 ..< len(typ.n):
-    assert(typ.n.sons[i].kind == nkSym)
-    var param = typ.n.sons[i].sym
+  for i in 1..<typ.n.len:
+    assert(typ.n[i].kind == nkSym)
+    var param = typ.n[i].sym
     if isCompileTimeOnly(param.typ): continue
-    if result != nil: add(result, ", ")
+    if result != nil: result.add(", ")
     var name = mangleName(p.module, param)
-    add(result, name)
+    result.add(name)
     if mapType(param.typ) == etyBaseIndex:
-      add(result, ", ")
-      add(result, name)
-      add(result, "_Idx")
+      result.add(", ")
+      result.add(name)
+      result.add("_Idx")
 
 proc countJsParams(typ: PType): int =
-  for i in 1 ..< len(typ.n):
-    assert(typ.n.sons[i].kind == nkSym)
-    var param = typ.n.sons[i].sym
+  for i in 1..<typ.n.len:
+    assert(typ.n[i].kind == nkSym)
+    var param = typ.n[i].sym
     if isCompileTimeOnly(param.typ): continue
     if mapType(param.typ) == etyBaseIndex:
       inc result, 2
@@ -1028,7 +1024,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
     lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
 
 proc genAsgn(p: PProc, n: PNode) =
-  genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=false)
+  genAsgnAux(p, n[0], n[1], noCopyNeeded=false)
 
 proc genFastAsgn(p: PProc, n: PNode) =
   # 'shallowCopy' always produced 'noCopyNeeded = true' here but this is wrong
@@ -1039,14 +1035,14 @@ proc genFastAsgn(p: PProc, n: PNode) =
   # here for 'shallowCopy'. This is an educated guess and might require further
   # changes later:
   let noCopy = n[0].typ.skipTypes(abstractInst).kind in {tySequence, tyOpt, tyString}
-  genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=noCopy)
+  genAsgnAux(p, n[0], n[1], noCopyNeeded=noCopy)
 
 proc genSwap(p: PProc, n: PNode) =
   var a, b: TCompRes
-  gen(p, n.sons[1], a)
-  gen(p, n.sons[2], b)
+  gen(p, n[1], a)
+  gen(p, n[2], b)
   var tmp = p.getTemp(false)
-  if mapType(p, skipTypes(n.sons[1].typ, abstractVar)) == etyBaseIndex:
+  if mapType(p, skipTypes(n[1].typ, abstractVar)) == etyBaseIndex:
     let tmp2 = p.getTemp(false)
     if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
       internalError(p.config, n.info, "genSwap")
@@ -1065,13 +1061,13 @@ proc getFieldPosition(p: PProc; f: PNode): int =
 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
-  gen(p, b.sons[0], a)
-  if skipTypes(b.sons[0].typ, abstractVarRange).kind == tyTuple:
-    r.res = makeJSString("Field" & $getFieldPosition(p, b.sons[1]))
+  let b = if n.kind == nkHiddenAddr: n[0] else: n
+  gen(p, b[0], a)
+  if skipTypes(b[0].typ, abstractVarRange).kind == tyTuple:
+    r.res = makeJSString("Field" & $getFieldPosition(p, b[1]))
   else:
-    if b.sons[1].kind != nkSym: internalError(p.config, b.sons[1].info, "genFieldAddr")
-    var f = b.sons[1].sym
+    if b[1].kind != nkSym: internalError(p.config, b[1].info, "genFieldAddr")
+    var f = b[1].sym
     if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
     r.res = makeJSString($f.loc.r)
   internalAssert p.config, a.typ != etyBaseIndex
@@ -1079,9 +1075,9 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
   r.kind = resExpr
 
 proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
-  gen(p, n.sons[0], r)
+  gen(p, n[0], r)
   r.typ = mapType(n.typ)
-  let otyp = skipTypes(n.sons[0].typ, abstractVarRange)
+  let otyp = skipTypes(n[0].typ, abstractVarRange)
 
   template mkTemp(i: int) =
     if r.typ == etyBaseIndex:
@@ -1095,11 +1091,11 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
         r.res = "$1[1]" % [r.res]
   if otyp.kind == tyTuple:
     r.res = ("$1.Field$2") %
-        [r.res, getFieldPosition(p, n.sons[1]).rope]
+        [r.res, getFieldPosition(p, n[1]).rope]
     mkTemp(0)
   else:
-    if n.sons[1].kind != nkSym: internalError(p.config, n.sons[1].info, "genFieldAccess")
-    var f = n.sons[1].sym
+    if n[1].kind != nkSym: internalError(p.config, n[1].info, "genFieldAccess")
+    var f = n[1].sym
     if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
     r.res = "$1.$2" % [r.res, f.loc.r]
     mkTemp(1)
@@ -1158,15 +1154,15 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
     a, b: TCompRes
     first: Int128
   r.typ = etyBaseIndex
-  let m = if n.kind == nkHiddenAddr: n.sons[0] else: n
-  gen(p, m.sons[0], a)
-  gen(p, m.sons[1], b)
+  let m = if n.kind == nkHiddenAddr: n[0] else: n
+  gen(p, m[0], a)
+  gen(p, m[1], b)
   #internalAssert p.config, a.typ != etyBaseIndex and b.typ != etyBaseIndex
   let (x, tmp) = maybeMakeTemp(p, m[0], a)
   r.address = x
-  var typ = skipTypes(m.sons[0].typ, abstractPtrs)
+  var typ = skipTypes(m[0].typ, abstractPtrs)
   if typ.kind == tyArray:
-    first = firstOrd(p.config, typ.sons[0])
+    first = firstOrd(p.config, typ[0])
   if optBoundsCheck in p.options:
     useMagic(p, "chckIndx")
     r.res = "chckIndx($1, $2, ($3 != null ? $3.length : 0)+$2-1)-$2" % [b.res, rope(first), tmp]
@@ -1177,7 +1173,7 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
   r.kind = resExpr
 
 proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) =
-  var ty = skipTypes(n.sons[0].typ, abstractVarRange)
+  var ty = skipTypes(n[0].typ, abstractVarRange)
   if ty.kind in {tyRef, tyPtr, tyLent, tyOwned}: ty = skipTypes(ty.lastSon, abstractVarRange)
   case ty.kind
   of tyArray, tyOpenArray, tySequence, tyString, tyCString, tyVarargs:
@@ -1212,9 +1208,9 @@ template isIndirect(x: PSym): bool =
                   skConst, skTemp, skLet})
 
 proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
-  case n.sons[0].kind
+  case n[0].kind
   of nkSym:
-    let s = n.sons[0].sym
+    let s = n[0].sym
     if s.loc.r == nil: internalError(p.config, n.info, "genAddr: 3")
     case s.kind
     of skVar, skLet, skResult:
@@ -1236,36 +1232,36 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
         r.res = rope("0")
       else:
         # 'var openArray' for instance produces an 'addr' but this is harmless:
-        gen(p, n.sons[0], r)
+        gen(p, n[0], r)
         #internalError(p.config, n.info, "genAddr: 4 " & renderTree(n))
     else: internalError(p.config, n.info, "genAddr: 2")
   of nkCheckedFieldExpr:
     genCheckedFieldOp(p, n[0], n.typ, r)
   of nkDotExpr:
     if mapType(p, n.typ) == etyBaseIndex:
-      genFieldAddr(p, n.sons[0], r)
+      genFieldAddr(p, n[0], r)
     else:
-      genFieldAccess(p, n.sons[0], r)
+      genFieldAccess(p, n[0], r)
   of nkBracketExpr:
-    var ty = skipTypes(n.sons[0].typ, abstractVarRange)
+    var ty = skipTypes(n[0].typ, abstractVarRange)
     if ty.kind in MappedToObject:
-      gen(p, n.sons[0], r)
+      gen(p, n[0], r)
     else:
-      let kindOfIndexedExpr = skipTypes(n.sons[0].sons[0].typ, abstractVarRange).kind
+      let kindOfIndexedExpr = skipTypes(n[0][0].typ, abstractVarRange).kind
       case kindOfIndexedExpr
       of tyArray, tyOpenArray, tySequence, tyString, tyCString, tyVarargs:
-        genArrayAddr(p, n.sons[0], r)
+        genArrayAddr(p, n[0], r)
       of tyTuple:
-        genFieldAddr(p, n.sons[0], r)
-      else: internalError(p.config, n.sons[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
+        genFieldAddr(p, n[0], r)
+      else: internalError(p.config, n[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
   of nkObjDownConv:
-    gen(p, n.sons[0], r)
+    gen(p, n[0], r)
   of nkHiddenDeref:
-    gen(p, n.sons[0].sons[0], r)
-  else: internalError(p.config, n.sons[0].info, "genAddr: " & $n.sons[0].kind)
+    gen(p, n[0][0], r)
+  else: internalError(p.config, n[0].info, "genAddr: " & $n[0].kind)
 
 proc attachProc(p: PProc; content: Rope; s: PSym) =
-  add(p.g.code, content)
+  p.g.code.add(content)
 
 proc attachProc(p: PProc; s: PSym) =
   let newp = genProc(p, s)
@@ -1277,7 +1273,7 @@ proc genProcForSymIfNeeded(p: PProc, s: PSym) =
     var owner = p
     while owner != nil and owner.prc != s.owner:
       owner = owner.up
-    if owner != nil: add(owner.locals, newp)
+    if owner != nil: owner.locals.add(newp)
     else: attachProc(p, newp, s)
 
 proc genCopyForParamIfNeeded(p: PProc, n: PNode) =
@@ -1291,7 +1287,7 @@ proc genCopyForParamIfNeeded(p: PProc, n: PNode) =
     if owner.prc == s.owner:
       if not owner.generatedParamCopies.containsOrIncl(s.id):
         let copy = "$1 = nimCopy(null, $1, $2);$n" % [s.loc.r, genTypeInfo(p, s.typ)]
-        add(owner.locals, owner.indentLine(copy))
+        owner.locals.add(owner.indentLine(copy))
       return
     owner = owner.up
 
@@ -1352,7 +1348,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
   r.kind = resVal
 
 proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
-  let it = n.sons[0]
+  let it = n[0]
   let t = mapType(p, it.typ)
   if t == etyObject:
     gen(p, it, r)
@@ -1377,57 +1373,57 @@ proc genArgNoParam(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
   gen(p, n, a)
   if a.typ == etyBaseIndex:
-    add(r.res, a.address)
-    add(r.res, ", ")
-    add(r.res, a.res)
+    r.res.add(a.address)
+    r.res.add(", ")
+    r.res.add(a.res)
   else:
-    add(r.res, a.res)
+    r.res.add(a.res)
 
 proc genArg(p: PProc, n: PNode, param: PSym, r: var TCompRes; emitted: ptr int = nil) =
   var a: TCompRes
   gen(p, n, a)
   if skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs} and
       a.typ == etyBaseIndex:
-    add(r.res, "$1[$2]" % [a.address, a.res])
+    r.res.add("$1[$2]" % [a.address, a.res])
   elif a.typ == etyBaseIndex:
-    add(r.res, a.address)
-    add(r.res, ", ")
-    add(r.res, a.res)
+    r.res.add(a.address)
+    r.res.add(", ")
+    r.res.add(a.res)
     if emitted != nil: inc emitted[]
   elif n.typ.kind in {tyVar, tyPtr, tyRef, tyLent, tyOwned} and
       n.kind in nkCallKinds and mapType(param.typ) == etyBaseIndex:
     # this fixes bug #5608:
     let tmp = getTemp(p)
-    add(r.res, "($1 = $2, $1[0]), $1[1]" % [tmp, a.rdLoc])
+    r.res.add("($1 = $2, $1[0]), $1[1]" % [tmp, a.rdLoc])
     if emitted != nil: inc emitted[]
   else:
-    add(r.res, a.res)
+    r.res.add(a.res)
 
 proc genArgs(p: PProc, n: PNode, r: var TCompRes; start=1) =
-  add(r.res, "(")
+  r.res.add("(")
   var hasArgs = false
 
-  var typ = skipTypes(n.sons[0].typ, abstractInst)
+  var typ = skipTypes(n[0].typ, abstractInst)
   assert(typ.kind == tyProc)
-  assert(len(typ) == len(typ.n))
+  assert(typ.len == typ.n.len)
   var emitted = start-1
 
-  for i in start ..< len(n):
-    let it = n.sons[i]
+  for i in start..<n.len:
+    let it = n[i]
     var paramType: PNode = nil
-    if i < len(typ):
-      assert(typ.n.sons[i].kind == nkSym)
-      paramType = typ.n.sons[i]
+    if i < typ.len:
+      assert(typ.n[i].kind == nkSym)
+      paramType = typ.n[i]
       if paramType.typ.isCompileTimeOnly: continue
 
-    if hasArgs: add(r.res, ", ")
+    if hasArgs: r.res.add(", ")
     if paramType.isNil:
       genArgNoParam(p, it, r)
     else:
       genArg(p, it, paramType.sym, r, addr emitted)
     inc emitted
     hasArgs = true
-  add(r.res, ")")
+  r.res.add(")")
   when false:
     # XXX look into this:
     let jsp = countJsParams(typ)
@@ -1443,9 +1439,9 @@ proc genOtherArg(p: PProc; n: PNode; i: int; typ: PType;
         " but got only: " & $(n.len-1))
   let it = n[i]
   var paramType: PNode = nil
-  if i < len(typ):
-    assert(typ.n.sons[i].kind == nkSym)
-    paramType = typ.n.sons[i]
+  if i < typ.len:
+    assert(typ.n[i].kind == nkSym)
+    paramType = typ.n[i]
     if paramType.typ.isCompileTimeOnly: return
   if paramType.isNil:
     genArgNoParam(p, it, r)
@@ -1462,8 +1458,8 @@ proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
     case pat[i]
     of '@':
       var generated = 0
-      for k in j ..< n.len:
-        if generated > 0: add(r.res, ", ")
+      for k in j..<n.len:
+        if generated > 0: r.res.add(", ")
         genOtherArg(p, n, k, typ, generated, r)
       inc i
     of '#':
@@ -1473,11 +1469,11 @@ proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
       inc i
     of '\31':
       # unit separator
-      add(r.res, "#")
+      r.res.add("#")
       inc i
     of '\29':
       # group separator
-      add(r.res, "@")
+      r.res.add("@")
       inc i
     else:
       let start = i
@@ -1485,36 +1481,36 @@ proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
         if pat[i] notin {'@', '#', '\31', '\29'}: inc(i)
         else: break
       if i - 1 >= start:
-        add(r.res, substr(pat, start, i - 1))
+        r.res.add(substr(pat, start, i - 1))
 
 proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
   # don't call '$' here for efficiency:
   let f = n[0].sym
   if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
   if sfInfixCall in f.flags:
-    let pat = n.sons[0].sym.loc.r.data
+    let pat = n[0].sym.loc.r.data
     internalAssert p.config, pat.len > 0
     if pat.contains({'#', '(', '@'}):
-      var typ = skipTypes(n.sons[0].typ, abstractInst)
+      var typ = skipTypes(n[0].typ, abstractInst)
       assert(typ.kind == tyProc)
       genPatternCall(p, n, pat, typ, r)
       return
   if n.len != 1:
-    gen(p, n.sons[1], r)
+    gen(p, n[1], r)
     if r.typ == etyBaseIndex:
       if r.address == nil:
         globalError(p.config, n.info, "cannot invoke with infix syntax")
       r.res = "$1[$2]" % [r.address, r.res]
       r.address = nil
       r.typ = etyNone
-    add(r.res, ".")
+    r.res.add(".")
   var op: TCompRes
-  gen(p, n.sons[0], op)
-  add(r.res, op.res)
+  gen(p, n[0], op)
+  r.res.add(op.res)
   genArgs(p, n, r, 2)
 
 proc genCall(p: PProc, n: PNode, r: var TCompRes) =
-  gen(p, n.sons[0], r)
+  gen(p, n[0], r)
   genArgs(p, n, r)
   if n.typ != nil:
     let t = mapType(n.typ)
@@ -1530,13 +1526,13 @@ proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
   internalAssert p.config, n.kind == nkBracket
   useMagic(p, "toJSStr") # Used in rawEcho
   useMagic(p, "rawEcho")
-  add(r.res, "rawEcho(")
-  for i in 0 ..< len(n):
-    let it = n.sons[i]
+  r.res.add("rawEcho(")
+  for i in 0..<n.len:
+    let it = n[i]
     if it.typ.isCompileTimeOnly: continue
-    if i > 0: add(r.res, ", ")
+    if i > 0: r.res.add(", ")
     genArgNoParam(p, it, r)
-  add(r.res, ")")
+  r.res.add(")")
   r.kind = resExpr
 
 proc putToSeq(s: string, indirect: bool): Rope =
@@ -1547,12 +1543,12 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope
 proc createRecordVarAux(p: PProc, rec: PNode, excludedFieldIDs: IntSet, output: var Rope) =
   case rec.kind
   of nkRecList:
-    for i in 0 ..< len(rec):
-      createRecordVarAux(p, rec.sons[i], excludedFieldIDs, output)
+    for i in 0..<rec.len:
+      createRecordVarAux(p, rec[i], excludedFieldIDs, output)
   of nkRecCase:
-    createRecordVarAux(p, rec.sons[0], excludedFieldIDs, output)
-    for i in 1 ..< len(rec):
-      createRecordVarAux(p, lastSon(rec.sons[i]), excludedFieldIDs, output)
+    createRecordVarAux(p, rec[0], excludedFieldIDs, output)
+    for i in 1..<rec.len:
+      createRecordVarAux(p, lastSon(rec[i]), excludedFieldIDs, output)
   of nkSym:
     # Do not produce code for void types
     if isEmptyType(rec.sym.typ): return
@@ -1566,11 +1562,11 @@ proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: v
   var t = typ
   if objHasTypeField(t):
     if output.len > 0: output.add(", ")
-    addf(output, "m_type: $1", [genTypeInfo(p, t)])
+    output.addf("m_type: $1", [genTypeInfo(p, t)])
   while t != nil:
     t = t.skipTypes(skipPtrs)
     createRecordVarAux(p, t.n, excludedFieldIDs, output)
-    t = t.sons[0]
+    t = t[0]
 
 proc arrayTypeForElemType(typ: PType): string =
   # XXX This should also support tyEnum and tyBool
@@ -1616,18 +1612,18 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
       result = rope("[")
       var i = 0
       while i < length:
-        if i > 0: add(result, ", ")
-        add(result, createVar(p, e, false))
+        if i > 0: result.add(", ")
+        result.add(createVar(p, e, false))
         inc(i)
-      add(result, "]")
+      result.add("]")
     if indirect: result = "[$1]" % [result]
   of tyTuple:
     result = rope("{")
     for i in 0..<t.len:
-      if i > 0: add(result, ", ")
-      addf(result, "Field$1: $2", [i.rope,
-            createVar(p, t.sons[i], false)])
-    add(result, "}")
+      if i > 0: result.add(", ")
+      result.addf("Field$1: $2", [i.rope,
+            createVar(p, t[i], false)])
+    result.add("}")
     if indirect: result = "[$1]" % [result]
   of tyObject:
     var initList: Rope
@@ -1724,20 +1720,20 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
     lineF(p, "}$n")
 
 proc genVarStmt(p: PProc, n: PNode) =
-  for i in 0 ..< len(n):
-    var a = n.sons[i]
+  for i in 0..<n.len:
+    var a = n[i]
     if a.kind != nkCommentStmt:
       if a.kind == nkVarTuple:
         let unpacked = lowerTupleUnpacking(p.module.graph, a, p.prc)
         genStmt(p, unpacked)
       else:
         assert(a.kind == nkIdentDefs)
-        assert(a.sons[0].kind == nkSym)
-        var v = a.sons[0].sym
+        assert(a[0].kind == nkSym)
+        var v = a[0].sym
         if lfNoDecl notin v.loc.flags and sfImportc notin v.flags:
           genLineDir(p, a)
           if sfCompileTime notin v.flags:
-            genVarInit(p, v, a.sons[2])
+            genVarInit(p, v, a[2])
           else:
             # lazy emit, done when it's actually used.
             if v.ast == nil: v.ast = a[2]
@@ -1748,13 +1744,13 @@ proc genConstant(p: PProc, c: PSym) =
     p.body = nil
     #genLineDir(p, c.ast)
     genVarInit(p, c, c.ast)
-    add(p.g.constants, p.body)
+    p.g.constants.add(p.body)
     p.body = oldBody
 
 proc genNew(p: PProc, n: PNode) =
   var a: TCompRes
-  gen(p, n.sons[1], a)
-  var t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
+  gen(p, n[1], a)
+  var t = skipTypes(n[1].typ, abstractVar)[0]
   if mapType(t) == etyObject:
     lineF(p, "$1 = $2;$n", [a.rdLoc, createVar(p, t, false)])
   elif a.typ == etyBaseIndex:
@@ -1764,37 +1760,37 @@ proc genNew(p: PProc, n: PNode) =
 
 proc genNewSeq(p: PProc, n: PNode) =
   var x, y: TCompRes
-  gen(p, n.sons[1], x)
-  gen(p, n.sons[2], y)
-  let t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
+  gen(p, n[1], x)
+  gen(p, n[2], y)
+  let t = skipTypes(n[1].typ, abstractVar)[0]
   lineF(p, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}", [
     x.rdLoc, y.rdLoc, createVar(p, t, false)])
 
 proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
-  case skipTypes(n.sons[1].typ, abstractVar).kind
-  of tyEnum, tyInt..tyUInt64, tyChar: gen(p, n.sons[1], r)
+  case skipTypes(n[1].typ, abstractVar).kind
+  of tyEnum, tyInt..tyUInt64, tyChar: gen(p, n[1], r)
   of tyBool: unaryExpr(p, n, r, "", "($1 ? 1:0)")
   else: internalError(p.config, n.info, "genOrd")
 
 proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
 
-  gen(p, n.sons[1], a)
+  gen(p, n[1], a)
   r.kind = resExpr
-  if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyChar:
+  if skipTypes(n[1].typ, abstractVarRange).kind == tyChar:
     r.res.add("[$1].concat(" % [a.res])
   else:
     r.res.add("($1 || []).concat(" % [a.res])
 
-  for i in 2 .. len(n) - 2:
-    gen(p, n.sons[i], a)
-    if skipTypes(n.sons[i].typ, abstractVarRange).kind == tyChar:
+  for i in 2..<n.len - 1:
+    gen(p, n[i], a)
+    if skipTypes(n[i].typ, abstractVarRange).kind == tyChar:
       r.res.add("[$1]," % [a.res])
     else:
       r.res.add("$1 || []," % [a.res])
 
-  gen(p, n.sons[len(n) - 1], a)
-  if skipTypes(n.sons[len(n) - 1].typ, abstractVarRange).kind == tyChar:
+  gen(p, n[^1], a)
+  if skipTypes(n[^1].typ, abstractVarRange).kind == tyChar:
     r.res.add("[$1])" % [a.res])
   else:
     r.res.add("$1 || [])" % [a.res])
@@ -1806,7 +1802,7 @@ proc genToArray(p: PProc; n: PNode; r: var TCompRes) =
   r.res = rope("array(")
   let x = skipConv(n[1])
   if x.kind == nkBracket:
-    for i in 0 ..< x.len:
+    for i in 0..<x.len:
       let it = x[i]
       if it.kind in {nkPar, nkTupleConstr} and it.len == 2:
         if i > 0: r.res.add(", ")
@@ -1821,28 +1817,28 @@ proc genToArray(p: PProc; n: PNode; r: var TCompRes) =
 
 proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = nil) =
   useMagic(p, magic)
-  add(r.res, magic & "(")
+  r.res.add(magic & "(")
   var a: TCompRes
 
-  gen(p, n.sons[1], a)
+  gen(p, n[1], a)
   if magic == "reprAny":
     # the pointer argument in reprAny is expandend to
     # (pointedto, pointer), so we need to fill it
     if a.address.isNil:
-      add(r.res, a.res)
-      add(r.res, ", null")
+      r.res.add(a.res)
+      r.res.add(", null")
     else:
-      add(r.res, "$1, $2" % [a.address, a.res])
+      r.res.add("$1, $2" % [a.address, a.res])
   else:
-    add(r.res, a.res)
+    r.res.add(a.res)
 
   if not typ.isNil:
-    add(r.res, ", ")
-    add(r.res, typ)
-  add(r.res, ")")
+    r.res.add(", ")
+    r.res.add(typ)
+  r.res.add(")")
 
 proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
-  let t = skipTypes(n.sons[1].typ, abstractVarRange)
+  let t = skipTypes(n[1].typ, abstractVarRange)
   case t.kind:
   of tyInt..tyInt64, tyUInt..tyUInt64:
     genReprAux(p, n, r, "reprInt")
@@ -1869,9 +1865,9 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
 
 proc genOf(p: PProc, n: PNode, r: var TCompRes) =
   var x: TCompRes
-  let t = skipTypes(n.sons[2].typ,
+  let t = skipTypes(n[2].typ,
                     abstractVarRange+{tyRef, tyPtr, tyLent, tyTypeDesc, tyOwned})
-  gen(p, n.sons[1], x)
+  gen(p, n[1], x)
   if tfFinal in t.flags:
     r.res = "($1.m_type == $2)" % [x.res, genTypeInfo(p, t)]
   else:
@@ -1886,22 +1882,22 @@ proc genDefault(p: PProc, n: PNode; r: var TCompRes) =
 proc genReset(p: PProc, n: PNode) =
   var x: TCompRes
   useMagic(p, "genericReset")
-  gen(p, n.sons[1], x)
+  gen(p, n[1], x)
   if x.typ == etyBaseIndex:
     lineF(p, "$1 = null, $2 = 0;$n", [x.address, x.res])
   else:
     let (a, tmp) = maybeMakeTemp(p, n[1], x)
     lineF(p, "$1 = genericReset($3, $2);$n", [a,
-                  genTypeInfo(p, n.sons[1].typ), tmp])
+                  genTypeInfo(p, n[1].typ), tmp])
 
 proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
   var
     a: TCompRes
     line, filen: Rope
-  var op = n.sons[0].sym.magic
+  var op = n[0].sym.magic
   case op
-  of mOr: genOr(p, n.sons[1], n.sons[2], r)
-  of mAnd: genAnd(p, n.sons[1], n.sons[2], r)
+  of mOr: genOr(p, n[1], n[2], r)
+  of mAnd: genAnd(p, n[1], n[2], r)
   of mAddI..mStrToStr: arith(p, n, r, op)
   of mRepr: genRepr(p, n, r)
   of mSwap: genSwap(p, n)
@@ -1919,7 +1915,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
 
     let rhsIsLit = n[2].kind in nkStrKinds
     let (a, tmp) = maybeMakeTemp(p, n[1], lhs)
-    if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:
+    if skipTypes(n[1].typ, abstractVarRange).kind == tyCString:
       r.res = "if ($1 != null) { $4 += $2; } else { $4 = $2$3; }" % [
         a, rhs.rdLoc, if rhsIsLit: nil else: ~".slice()", tmp]
     else:
@@ -1928,8 +1924,8 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
     r.kind = resExpr
   of mAppendSeqElem:
     var x, y: TCompRes
-    gen(p, n.sons[1], x)
-    gen(p, n.sons[2], y)
+    gen(p, n[1], x)
+    gen(p, n[2], y)
     let (a, tmp) = maybeMakeTemp(p, n[1], x)
     if mapType(n[2].typ) == etyBaseIndex:
       let c = "[$1, $2]" % [y.address, y.res]
@@ -1961,13 +1957,13 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
       r.res = "($# == null && $# === 0)" % [x.address, x.res]
   of mEnumToStr: genRepr(p, n, r)
   of mNew, mNewFinalize: genNew(p, n)
-  of mChr: gen(p, n.sons[1], r)
+  of mChr: gen(p, n[1], r)
   of mArrToSeq:
-    if needsNoCopy(p, n.sons[1]):
-      gen(p, n.sons[1], r)
+    if needsNoCopy(p, n[1]):
+      gen(p, n[1], r)
     else:
       var x: TCompRes
-      gen(p, n.sons[1], x)
+      gen(p, n[1], x)
       useMagic(p, "nimCopy")
       r.res = "nimCopy(null, $1, $2)" % [x.rdLoc, genTypeInfo(p, n.typ)]
   of mDestroy: discard "ignore calls to the default destructor"
@@ -1994,9 +1990,9 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
     binaryExpr(p, n, r, "mnewString", "($1 == null ? $3 = mnewString($2) : $3.length = $2)")
   of mSetLengthSeq:
     var x, y: TCompRes
-    gen(p, n.sons[1], x)
-    gen(p, n.sons[2], y)
-    let t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
+    gen(p, n[1], x)
+    gen(p, n[2], y)
+    let t = skipTypes(n[1].typ, abstractVar)[0]
     let (a, tmp) = maybeMakeTemp(p, n[1], x)
     let (b, tmp2) = maybeMakeTemp(p, n[2], y)
     r.res = """if ($1 === null) $4 = [];
@@ -2021,14 +2017,14 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
   of mReset: genReset(p, n)
   of mEcho: genEcho(p, n, r)
   of mNLen..mNError, mSlurp, mStaticExec:
-    localError(p.config, n.info, errXMustBeCompileTime % n.sons[0].sym.name.s)
+    localError(p.config, n.info, errXMustBeCompileTime % n[0].sym.name.s)
   of mCopyStr:
     binaryExpr(p, n, r, "", "($1.slice($2))")
   of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)")
   of mNewStringOfCap:
     unaryExpr(p, n, r, "mnewString", "mnewString(0)")
   of mDotDot:
-    genProcForSymIfNeeded(p, n.sons[0].sym)
+    genProcForSymIfNeeded(p, n[0].sym)
     genCall(p, n, r)
   of mParseBiggestFloat:
     useMagic(p, "nimParseBiggestFloat")
@@ -2036,9 +2032,9 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
   of mSlice:
     # arr.slice([begin[, end]]): 'end' is exclusive
     var x, y, z: TCompRes
-    gen(p, n.sons[1], x)
-    gen(p, n.sons[2], y)
-    gen(p, n.sons[3], z)
+    gen(p, n[1], x)
+    gen(p, n[2], y)
+    gen(p, n[3], z)
     r.res = "($1.slice($2, $3+1))" % [x.rdLoc, y.rdLoc, z.rdLoc]
     r.kind = resExpr
   else:
@@ -2051,58 +2047,58 @@ proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) =
   useMagic(p, "setConstr")
   r.res = rope("setConstr(")
   r.kind = resExpr
-  for i in 0 ..< len(n):
-    if i > 0: add(r.res, ", ")
-    var it = n.sons[i]
+  for i in 0..<n.len:
+    if i > 0: r.res.add(", ")
+    var it = n[i]
     if it.kind == nkRange:
-      gen(p, it.sons[0], a)
-      gen(p, it.sons[1], b)
-      addf(r.res, "[$1, $2]", [a.res, b.res])
+      gen(p, it[0], a)
+      gen(p, it[1], b)
+      r.res.addf("[$1, $2]", [a.res, b.res])
     else:
       gen(p, it, a)
-      add(r.res, a.res)
-  add(r.res, ")")
+      r.res.add(a.res)
+  r.res.add(")")
   # emit better code for constant sets:
   if isDeepConstExpr(n):
     inc(p.g.unique)
     let tmp = rope("ConstSet") & rope(p.g.unique)
-    addf(p.g.constants, "var $1 = $2;$n", [tmp, r.res])
+    p.g.constants.addf("var $1 = $2;$n", [tmp, r.res])
     r.res = tmp
 
 proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
   r.res = rope("[")
   r.kind = resExpr
-  for i in 0 ..< len(n):
-    if i > 0: add(r.res, ", ")
-    gen(p, n.sons[i], a)
+  for i in 0..<n.len:
+    if i > 0: r.res.add(", ")
+    gen(p, n[i], a)
     if a.typ == etyBaseIndex:
-      addf(r.res, "[$1, $2]", [a.address, a.res])
+      r.res.addf("[$1, $2]", [a.address, a.res])
     else:
       if not needsNoCopy(p, n[i]):
         let typ = n[i].typ.skipTypes(abstractInst)
         useMagic(p, "nimCopy")
         a.res = "nimCopy(null, $1, $2)" % [a.rdLoc, genTypeInfo(p, typ)]
-      add(r.res, a.res)
-  add(r.res, "]")
+      r.res.add(a.res)
+  r.res.add("]")
 
 proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
   r.res = rope("{")
   r.kind = resExpr
-  for i in 0 ..< len(n):
-    if i > 0: add(r.res, ", ")
-    var it = n.sons[i]
-    if it.kind == nkExprColonExpr: it = it.sons[1]
+  for i in 0..<n.len:
+    if i > 0: r.res.add(", ")
+    var it = n[i]
+    if it.kind == nkExprColonExpr: it = it[1]
     gen(p, it, a)
     let typ = it.typ.skipTypes(abstractInst)
     if a.typ == etyBaseIndex:
-      addf(r.res, "Field$#: [$#, $#]", [i.rope, a.address, a.res])
+      r.res.addf("Field$#: [$#, $#]", [i.rope, a.address, a.res])
     else:
       if not needsNoCopy(p, it):
         useMagic(p, "nimCopy")
         a.res = "nimCopy(null, $1, $2)" % [a.rdLoc, genTypeInfo(p, typ)]
-      addf(r.res, "Field$#: $#", [i.rope, a.res])
+      r.res.addf("Field$#: $#", [i.rope, a.res])
   r.res.add("}")
 
 proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
@@ -2110,32 +2106,32 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
   r.kind = resExpr
   var initList : Rope
   var fieldIDs = initIntSet()
-  for i in 1 ..< len(n):
-    if i > 1: add(initList, ", ")
-    var it = n.sons[i]
+  for i in 1..<n.len:
+    if i > 1: initList.add(", ")
+    var it = n[i]
     internalAssert p.config, it.kind == nkExprColonExpr
-    let val = it.sons[1]
+    let val = it[1]
     gen(p, val, a)
-    var f = it.sons[0].sym
+    var f = it[0].sym
     if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
     fieldIDs.incl(f.id)
 
     let typ = val.typ.skipTypes(abstractInst)
     if a.typ == etyBaseIndex:
-      addf(initList, "$#: [$#, $#]", [f.loc.r, a.address, a.res])
+      initList.addf("$#: [$#, $#]", [f.loc.r, a.address, a.res])
     else:
       if not needsNoCopy(p, val):
         useMagic(p, "nimCopy")
         a.res = "nimCopy(null, $1, $2)" % [a.rdLoc, genTypeInfo(p, typ)]
-      addf(initList, "$#: $#", [f.loc.r, a.res])
+      initList.addf("$#: $#", [f.loc.r, a.res])
   let t = skipTypes(n.typ, abstractInst + skipPtrs)
   createObjInitList(p, t, fieldIDs, initList)
   r.res = ("{$1}") % [initList]
 
 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)
+  var src = skipTypes(n[1].typ, abstractVarRange)
+  gen(p, n[1], r)
   if dest.kind == src.kind:
     # no-op conversion
     return
@@ -2150,17 +2146,17 @@ proc genConv(p: PProc, n: PNode, r: var TCompRes) =
     discard
 
 proc upConv(p: PProc, n: PNode, r: var TCompRes) =
-  gen(p, n.sons[0], r)        # XXX
+  gen(p, n[0], r)        # XXX
 
 proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) =
   var a, b: TCompRes
-  gen(p, n.sons[0], r)
+  gen(p, n[0], r)
   if optRangeCheck notin p.options or (skipTypes(n.typ, abstractVar).kind in {tyUInt..tyUInt64} and
       checkUnsignedConversions notin p.config.legacyFeatures):
     discard "XXX maybe emit masking instructions here"
   else:
-    gen(p, n.sons[1], a)
-    gen(p, n.sons[2], b)
+    gen(p, n[1], a)
+    gen(p, n[2], b)
     useMagic(p, "chckRange")
     r.res = "chckRange($1, $2, $3)" % [r.res, a.res, b.res]
     r.kind = resExpr
@@ -2168,10 +2164,10 @@ proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) =
 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:
-    gen(p, n.sons[0].sons[0], r)
+  if n[0].kind == nkCStringToString:
+    gen(p, n[0][0], r)
   else:
-    gen(p, n.sons[0], r)
+    gen(p, n[0], r)
     if r.res == nil: internalError(p.config, n.info, "convStrToCStr")
     useMagic(p, "toJSStr")
     r.res = "toJSStr($1)" % [r.res]
@@ -2180,10 +2176,10 @@ proc convStrToCStr(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:
-    gen(p, n.sons[0].sons[0], r)
+  if n[0].kind == nkStringToCString:
+    gen(p, n[0][0], r)
   else:
-    gen(p, n.sons[0], r)
+    gen(p, n[0], r)
     if r.res == nil: internalError(p.config, n.info, "convCStrToStr")
     useMagic(p, "cstrToNimstr")
     r.res = "cstrToNimstr($1)" % [r.res]
@@ -2192,8 +2188,8 @@ proc convCStrToStr(p: PProc, n: PNode, r: var TCompRes) =
 proc genReturnStmt(p: PProc, n: PNode) =
   if p.procDef == nil: internalError(p.config, n.info, "genReturnStmt")
   p.beforeRetNeeded = true
-  if n.sons[0].kind != nkEmpty:
-    genStmt(p, n.sons[0])
+  if n[0].kind != nkEmpty:
+    genStmt(p, n[0])
   else:
     genLineDir(p, n)
   lineF(p, "break BeforeRet;$n", [])
@@ -2220,12 +2216,12 @@ proc genProcBody(p: PProc, prc: PSym): Rope =
     result.add p.body
     result.add p.indentLine(~"} while (false);$n")
   else:
-    add(result, p.body)
+    result.add(p.body)
   if prc.typ.callConv == ccSysCall:
     result = ("try {$n$1} catch (e) {$n" &
       " alert(\"Unhandled exception:\\n\" + e.message + \"\\n\"$n}") % [result]
   if hasFrameInfo(p):
-    add(result, frameDestroy(p))
+    result.add(frameDestroy(p))
 
 proc optionalLine(p: Rope): Rope =
   if p == nil:
@@ -2245,8 +2241,8 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
   var resultAsgn: Rope = nil
   var name = mangleName(p.module, prc)
   let header = generateHeader(p, prc.typ)
-  if prc.typ.sons[0] != nil and sfPure notin prc.flags:
-    resultSym = prc.ast.sons[resultPos].sym
+  if prc.typ[0] != nil and sfPure notin prc.flags:
+    resultSym = prc.ast[resultPos].sym
     let mname = mangleName(p.module, resultSym)
     if not isIndirect(resultSym) and
       resultSym.typ.kind in {tyVar, tyPtr, tyLent, tyRef, tyOwned} and
@@ -2256,7 +2252,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
     else:
       let resVar = createVar(p, resultSym.typ, isIndirect(resultSym))
       resultAsgn = p.indentLine(("var $# = $#;$n") % [mname, resVar])
-    gen(p, prc.ast.sons[resultPos], a)
+    gen(p, prc.ast[resultPos], a)
     if mapType(p, resultSym.typ) == etyBaseIndex:
       returnStmt = "return [$#, $#];$n" % [a.address, a.res]
     else:
@@ -2316,13 +2312,13 @@ proc genStmt(p: PProc, n: PNode) =
 proc genPragma(p: PProc, n: PNode) =
   for it in n.sons:
     case whichPragma(it)
-    of wEmit: genAsmOrEmitStmt(p, it.sons[1])
+    of wEmit: genAsmOrEmitStmt(p, it[1])
     else: discard
 
 proc genCast(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)
+  var src = skipTypes(n[1].typ, abstractVarRange)
+  gen(p, n[1], r)
   if dest.kind == src.kind:
     # no-op conversion
     return
@@ -2410,9 +2406,9 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
     r.kind = resExpr
   of nkCallKinds:
     if isEmptyType(n.typ): genLineDir(p, n)
-    if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone):
+    if (n[0].kind == nkSym) and (n[0].sym.magic != mNone):
       genMagic(p, n, r)
-    elif n.sons[0].kind == nkSym and sfInfixCall in n.sons[0].sym.flags and
+    elif n[0].kind == nkSym and sfInfixCall in n[0].sym.flags and
         n.len >= 1:
       genInfixCall(p, n, r)
     else:
@@ -2429,7 +2425,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
   of nkBracketExpr: genArrayAccess(p, n, r)
   of nkDotExpr: genFieldAccess(p, n, r)
   of nkCheckedFieldExpr: genCheckedFieldOp(p, n, nil, r)
-  of nkObjDownConv: gen(p, n.sons[0], r)
+  of nkObjDownConv: gen(p, n[0], r)
   of nkObjUpConv: upConv(p, n, r)
   of nkCast: genCast(p, n, r)
   of nkChckRangeF: genRangeChck(p, n, r, "chckRangeF")
@@ -2439,26 +2435,26 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
   of nkCStringToString: convCStrToStr(p, n, r)
   of nkEmpty: discard
   of nkLambdaKinds:
-    let s = n.sons[namePos].sym
+    let s = n[namePos].sym
     discard mangleName(p.module, s)
     r.res = s.loc.r
     if lfNoDecl in s.loc.flags or s.magic != mNone: discard
     elif not p.g.generatedSyms.containsOrIncl(s.id):
-      add(p.locals, genProc(p, s))
+      p.locals.add(genProc(p, s))
   of nkType: r.res = genTypeInfo(p, n.typ)
   of nkStmtList, nkStmtListExpr:
     # this shows the distinction is nice for backends and should be kept
     # in the frontend
     let isExpr = not isEmptyType(n.typ)
-    for i in 0 ..< len(n) - isExpr.ord:
-      genStmt(p, n.sons[i])
+    for i in 0..<n.len - isExpr.ord:
+      genStmt(p, n[i])
     if isExpr:
       gen(p, lastSon(n), r)
   of nkBlockStmt, nkBlockExpr: genBlock(p, n, r)
   of nkIfStmt, nkIfExpr: genIf(p, n, r)
   of nkWhen:
     # This is "when nimvm" node
-    gen(p, n.sons[1].sons[0], r)
+    gen(p, n[1][0], r)
   of nkWhileStmt: genWhileStmt(p, n)
   of nkVarSection, nkLetSection: genVarStmt(p, n)
   of nkConstSection: discard
@@ -2470,9 +2466,9 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
   of nkAsgn: genAsgn(p, n)
   of nkFastAsgn: genFastAsgn(p, n)
   of nkDiscardStmt:
-    if n.sons[0].kind != nkEmpty:
+    if n[0].kind != nkEmpty:
       genLineDir(p, n)
-      gen(p, n.sons[0], r)
+      gen(p, n[0], r)
   of nkAsmStmt: genAsmOrEmitStmt(p, n)
   of nkTryStmt, nkHiddenTryStmt: genTry(p, n, r)
   of nkRaiseStmt: genRaiseStmt(p, n)
@@ -2481,9 +2477,9 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
      nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt: discard
   of nkPragma: genPragma(p, n)
   of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef:
-    var s = n.sons[namePos].sym
+    var s = n[namePos].sym
     if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}:
-      genSym(p, n.sons[namePos], r)
+      genSym(p, n[namePos], r)
       r.res = nil
   of nkGotoState, nkState:
     internalError(p.config, n.info, "first class iterators not implemented")
@@ -2541,7 +2537,7 @@ proc addHcrInitGuards(p: PProc, n: PNode,
 
 proc genModule(p: PProc, n: PNode) =
   if optStackTrace in p.options:
-    add(p.body, frameCreate(p,
+    p.body.add(frameCreate(p,
         makeJSString("module " & p.module.module.name.s),
         makeJSString(toFilename(p.config, p.module.module.info))))
   var transformedN = transformStmt(p.module.graph, p.module.module, n)
@@ -2565,7 +2561,7 @@ proc genModule(p: PProc, n: PNode) =
     genStmt(p, transformedN)
 
   if optStackTrace in p.options:
-    add(p.body, frameDestroy(p))
+    p.body.add(frameDestroy(p))
 
 proc myProcess(b: PPassContext, n: PNode): PNode =
   result = n
@@ -2576,8 +2572,8 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
   var p = newProc(globals, m, nil, m.module.options)
   p.unique = globals.unique
   genModule(p, n)
-  add(p.g.code, p.locals)
-  add(p.g.code, p.body)
+  p.g.code.add(p.locals)
+  p.g.code.add(p.body)
 
 proc wholeCode(graph: ModuleGraph; m: BModule): Rope =
   let globals = PGlobals(graph.backend)
@@ -2587,8 +2583,8 @@ proc wholeCode(graph: ModuleGraph; m: BModule): Rope =
       attachProc(p, prc)
 
   var disp = generateMethodDispatchers(graph)
-  for i in 0..len(disp)-1:
-    let prc = disp.sons[i].sym
+  for i in 0..<disp.len:
+    let prc = disp[i].sym
     if not globals.generatedSyms.containsOrIncl(prc.id):
       var p = newProc(globals, m, nil, m.module.options)
       attachProc(p, prc)
diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim
index 70d6c22ba..2073c252e 100644
--- a/compiler/jstypes.nim
+++ b/compiler/jstypes.nim
@@ -17,22 +17,20 @@ proc genTypeInfo(p: PProc, typ: PType): Rope
 proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
   var
     s, u: Rope
-    length: int
     field: PSym
     b: PNode
   result = nil
   case n.kind
   of nkRecList:
-    length = len(n)
-    if length == 1:
-      result = genObjectFields(p, typ, n.sons[0])
+    if n.len == 1:
+      result = genObjectFields(p, typ, n[0])
     else:
       s = nil
-      for i in 0 ..< length:
-        if i > 0: add(s, ", \L")
-        add(s, genObjectFields(p, typ, n.sons[i]))
+      for i in 0..<n.len:
+        if i > 0: s.add(", \L")
+        s.add(genObjectFields(p, typ, n[i]))
       result = ("{kind: 2, len: $1, offset: 0, " &
-          "typ: null, name: null, sons: [$2]}") % [rope(length), s]
+          "typ: null, name: null, sons: [$2]}") % [rope(n.len), s]
   of nkSym:
     field = n.sym
     s = genTypeInfo(p, field.typ)
@@ -41,29 +39,28 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
                    [mangleName(p.module, field), s,
                     makeJSString(field.name.s)]
   of nkRecCase:
-    length = len(n)
-    if (n.sons[0].kind != nkSym): internalError(p.config, n.info, "genObjectFields")
-    field = n.sons[0].sym
+    if (n[0].kind != nkSym): internalError(p.config, n.info, "genObjectFields")
+    field = n[0].sym
     s = genTypeInfo(p, field.typ)
-    for i in 1 ..< length:
-      b = n.sons[i]           # branch
+    for i in 1..<n.len:
+      b = n[i]           # branch
       u = nil
       case b.kind
       of nkOfBranch:
-        if len(b) < 2:
+        if b.len < 2:
           internalError(p.config, b.info, "genObjectFields; nkOfBranch broken")
-        for j in 0 .. len(b) - 2:
-          if u != nil: add(u, ", ")
-          if b.sons[j].kind == nkRange:
-            addf(u, "[$1, $2]", [rope(getOrdValue(b.sons[j].sons[0])),
-                                 rope(getOrdValue(b.sons[j].sons[1]))])
+        for j in 0..<b.len - 1:
+          if u != nil: u.add(", ")
+          if b[j].kind == nkRange:
+            u.addf("[$1, $2]", [rope(getOrdValue(b[j][0])),
+                                 rope(getOrdValue(b[j][1]))])
           else:
-            add(u, rope(getOrdValue(b.sons[j])))
+            u.add(rope(getOrdValue(b[j])))
       of nkElse:
         u = rope(lengthOrd(p.config, field.typ))
       else: internalError(p.config, n.info, "genObjectFields(nkRecCase)")
-      if result != nil: add(result, ", \L")
-      addf(result, "[setConstr($1), $2]",
+      if result != nil: result.add(", \L")
+      result.addf("[setConstr($1), $2]",
            [u, genObjectFields(p, typ, lastSon(b))])
     result = ("{kind: 3, offset: \"$1\", len: $3, " &
         "typ: $2, name: $4, sons: [$5]}") % [
@@ -72,27 +69,27 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
   else: internalError(p.config, n.info, "genObjectFields")
 
 proc objHasTypeField(t: PType): bool {.inline.} =
-  tfInheritable in t.flags or t.sons[0] != nil
+  tfInheritable in t.flags or t[0] != nil
 
 proc genObjectInfo(p: PProc, typ: PType, name: Rope) =
   let kind = if objHasTypeField(typ): tyObject else: tyTuple
   var s = ("var $1 = {size: 0, kind: $2, base: null, node: null, " &
            "finalizer: null};$n") % [name, rope(ord(kind))]
   prepend(p.g.typeInfo, s)
-  addf(p.g.typeInfo, "var NNI$1 = $2;$n",
+  p.g.typeInfo.addf("var NNI$1 = $2;$n",
        [rope(typ.id), genObjectFields(p, typ, typ.n)])
-  addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
-  if (typ.kind == tyObject) and (typ.sons[0] != nil):
-    addf(p.g.typeInfo, "$1.base = $2;$n",
-         [name, genTypeInfo(p, typ.sons[0].skipTypes(skipPtrs))])
+  p.g.typeInfo.addf("$1.node = NNI$2;$n", [name, rope(typ.id)])
+  if (typ.kind == tyObject) and (typ[0] != nil):
+    p.g.typeInfo.addf("$1.base = $2;$n",
+         [name, genTypeInfo(p, typ[0].skipTypes(skipPtrs))])
 
 proc genTupleFields(p: PProc, typ: PType): Rope =
   var s: Rope = nil
-  for i in 0 ..< typ.len:
-    if i > 0: add(s, ", \L")
+  for i in 0..<typ.len:
+    if i > 0: s.add(", \L")
     s.addf("{kind: 1, offset: \"Field$1\", len: 0, " &
            "typ: $2, name: \"Field$1\", sons: null}",
-           [i.rope, genTypeInfo(p, typ.sons[i])])
+           [i.rope, genTypeInfo(p, typ[i])])
   result = ("{kind: 2, len: $1, offset: 0, " &
             "typ: null, name: null, sons: [$2]}") % [rope(typ.len), s]
 
@@ -100,30 +97,29 @@ proc genTupleInfo(p: PProc, typ: PType, name: Rope) =
   var s = ("var $1 = {size: 0, kind: $2, base: null, node: null, " &
            "finalizer: null};$n") % [name, rope(ord(typ.kind))]
   prepend(p.g.typeInfo, s)
-  addf(p.g.typeInfo, "var NNI$1 = $2;$n",
+  p.g.typeInfo.addf("var NNI$1 = $2;$n",
        [rope(typ.id), genTupleFields(p, typ)])
-  addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
+  p.g.typeInfo.addf("$1.node = NNI$2;$n", [name, rope(typ.id)])
 
 proc genEnumInfo(p: PProc, typ: PType, name: Rope) =
-  let length = len(typ.n)
   var s: Rope = nil
-  for i in 0 ..< length:
-    if (typ.n.sons[i].kind != nkSym): internalError(p.config, typ.n.info, "genEnumInfo")
-    let field = typ.n.sons[i].sym
-    if i > 0: add(s, ", \L")
+  for i in 0..<typ.n.len:
+    if (typ.n[i].kind != nkSym): internalError(p.config, typ.n.info, "genEnumInfo")
+    let field = typ.n[i].sym
+    if i > 0: s.add(", \L")
     let extName = if field.ast == nil: field.name.s else: field.ast.strVal
-    addf(s, "\"$1\": {kind: 1, offset: $1, typ: $2, name: $3, len: 0, sons: null}",
+    s.addf("\"$1\": {kind: 1, offset: $1, typ: $2, name: $3, len: 0, sons: null}",
          [rope(field.position), name, makeJSString(extName)])
   var n = ("var NNI$1 = {kind: 2, offset: 0, typ: null, " &
-      "name: null, len: $2, sons: {$3}};$n") % [rope(typ.id), rope(length), s]
+      "name: null, len: $2, sons: {$3}};$n") % [rope(typ.id), rope(typ.n.len), s]
   s = ("var $1 = {size: 0, kind: $2, base: null, node: null, " &
        "finalizer: null};$n") % [name, rope(ord(typ.kind))]
   prepend(p.g.typeInfo, s)
-  add(p.g.typeInfo, n)
-  addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
-  if typ.sons[0] != nil:
-    addf(p.g.typeInfo, "$1.base = $2;$n",
-         [name, genTypeInfo(p, typ.sons[0])])
+  p.g.typeInfo.add(n)
+  p.g.typeInfo.addf("$1.node = NNI$2;$n", [name, rope(typ.id)])
+  if typ[0] != nil:
+    p.g.typeInfo.addf("$1.base = $2;$n",
+         [name, genTypeInfo(p, typ[0])])
 
 proc genTypeInfo(p: PProc, typ: PType): Rope =
   let t = typ.skipTypes({tyGenericInst, tyDistinct, tyAlias, tySink, tyOwned})
@@ -131,7 +127,7 @@ proc genTypeInfo(p: PProc, typ: PType): Rope =
   if containsOrIncl(p.g.typeInfoGenerated, t.id): return
   case t.kind
   of tyDistinct:
-    result = genTypeInfo(p, t.sons[0])
+    result = genTypeInfo(p, t[0])
   of tyPointer, tyProc, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64:
     var s =
       "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
@@ -142,15 +138,15 @@ proc genTypeInfo(p: PProc, typ: PType): Rope =
       "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
               [result, rope(ord(t.kind))]
     prepend(p.g.typeInfo, s)
-    addf(p.g.typeInfo, "$1.base = $2;$n",
+    p.g.typeInfo.addf("$1.base = $2;$n",
          [result, genTypeInfo(p, t.lastSon)])
   of tyArray:
     var s =
       "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
               [result, rope(ord(t.kind))]
     prepend(p.g.typeInfo, s)
-    addf(p.g.typeInfo, "$1.base = $2;$n",
-         [result, genTypeInfo(p, t.sons[1])])
+    p.g.typeInfo.addf("$1.base = $2;$n",
+         [result, genTypeInfo(p, t[1])])
   of tyEnum: genEnumInfo(p, t, result)
   of tyObject: genObjectInfo(p, t, result)
   of tyTuple: genTupleInfo(p, t, result)
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index f5fc4bb46..336d6c314 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -128,8 +128,8 @@ proc newCall(a: PSym, b: PNode): PNode =
 
 proc createClosureIterStateType*(g: ModuleGraph; iter: PSym): PType =
   var n = newNodeI(nkRange, iter.info)
-  addSon(n, newIntNode(nkIntLit, -1))
-  addSon(n, newIntNode(nkIntLit, 0))
+  n.add newIntNode(nkIntLit, -1)
+  n.add newIntNode(nkIntLit, 0)
   result = newType(tyRange, iter)
   result.n = n
   var intType = nilOrSysInt(g)
@@ -148,27 +148,27 @@ proc createEnvObj(g: ModuleGraph; owner: PSym; info: TLineInfo): PType =
 
 proc getClosureIterResult*(g: ModuleGraph; iter: PSym): PSym =
   if resultPos < iter.ast.len:
-    result = iter.ast.sons[resultPos].sym
+    result = iter.ast[resultPos].sym
   else:
     # XXX a bit hacky:
     result = newSym(skResult, getIdent(g.cache, ":result"), iter, iter.info, {})
-    result.typ = iter.typ.sons[0]
+    result.typ = iter.typ[0]
     incl(result.flags, sfUsed)
     iter.ast.add newSymNode(result)
 
 proc addHiddenParam(routine: PSym, param: PSym) =
   assert param.kind == skParam
-  var params = routine.ast.sons[paramsPos]
+  var params = routine.ast[paramsPos]
   # -1 is correct here as param.position is 0 based but we have at position 0
   # some nkEffect node:
   param.position = routine.typ.n.len-1
-  addSon(params, newSymNode(param))
+  params.add newSymNode(param)
   #incl(routine.typ.flags, tfCapturesEnv)
   assert sfFromGeneric in param.flags
   #echo "produced environment: ", param.id, " for ", routine.id
 
 proc getHiddenParam(g: ModuleGraph; routine: PSym): PSym =
-  let params = routine.ast.sons[paramsPos]
+  let params = routine.ast[paramsPos]
   let hidden = lastSon(params)
   if hidden.kind == nkSym and hidden.sym.kind == skParam and hidden.sym.name.s == paramName:
     result = hidden.sym
@@ -179,7 +179,7 @@ proc getHiddenParam(g: ModuleGraph; routine: PSym): PSym =
     result = routine
 
 proc getEnvParam*(routine: PSym): PSym =
-  let params = routine.ast.sons[paramsPos]
+  let params = routine.ast[paramsPos]
   let hidden = lastSon(params)
   if hidden.kind == nkSym and hidden.sym.name.s == paramName:
     result = hidden.sym
@@ -206,8 +206,8 @@ proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
   # which is however the only case when we generate an assignment in the first
   # place.
   result = newNodeI(nkAsgn, info, 2)
-  result.sons[0] = le
-  result.sons[1] = ri
+  result[0] = le
+  result[1] = ri
 
 proc makeClosure*(g: ModuleGraph; prc: PSym; env: PNode; info: TLineInfo): PNode =
   result = newNodeIT(nkClosure, info, prc.typ)
@@ -255,7 +255,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
   var env: PNode
   if owner.isIterator:
     let it = getHiddenParam(g, owner)
-    addUniqueField(it.typ.skipTypes({tyOwned}).sons[0], hp, g.cache)
+    addUniqueField(it.typ.skipTypes({tyOwned})[0], hp, g.cache)
     env = indirectAccess(newSymNode(it), hp, hp.info)
   else:
     let e = newSym(skLet, iter.name, owner, n.info)
@@ -520,7 +520,7 @@ proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
   if not envParam.isNil:
     var access = newSymNode(envParam)
     while true:
-      let obj = access.typ.sons[0]
+      let obj = access.typ[0]
       assert obj.kind == tyObject
       let field = getFieldFromObj(obj, s)
       if field != nil:
@@ -539,7 +539,7 @@ proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType; info: TLineInfo): PNo
   when false:
     if owner.kind == skIterator and owner.typ.callConv == ccClosure:
       let it = getHiddenParam(owner)
-      addUniqueField(it.typ.sons[0], v)
+      addUniqueField(it.typ[0], v)
       result = indirectAccess(newSymNode(it), v, v.info)
     else:
       result = newSymNode(v)
@@ -679,7 +679,7 @@ proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass;
     result = n
 
 proc getStateField*(g: ModuleGraph; owner: PSym): PSym =
-  getHiddenParam(g, owner).typ.skipTypes({tyOwned, tyRef, tyPtr}).n.sons[0].sym
+  getHiddenParam(g, owner).typ.skipTypes({tyOwned, tyRef, tyPtr}).n[0].sym
 
 proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
                       c: var LiftingPass): PNode
@@ -748,13 +748,13 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
     discard
   of nkClosure:
     if n[1].kind == nkNilLit:
-      n.sons[0] = liftCapturedVars(n[0], owner, d, c)
-      let x = n.sons[0].skipConv
+      n[0] = liftCapturedVars(n[0], owner, d, c)
+      let x = n[0].skipConv
       if x.kind == nkClosure:
         #localError(n.info, "internal error: closure to closure created")
         # now we know better, so patch it:
-        n.sons[0] = x.sons[0]
-        n.sons[1] = x.sons[1]
+        n[0] = x[0]
+        n[1] = x[1]
   of nkLambdaKinds, nkIteratorDef:
     if n.typ != nil and n[namePos].kind == nkSym:
       let oldInContainer = c.inContainer
@@ -765,29 +765,29 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
       c.inContainer = oldInContainer
   of nkHiddenStdConv:
     if n.len == 2:
-      n.sons[1] = liftCapturedVars(n[1], owner, d, c)
+      n[1] = liftCapturedVars(n[1], owner, d, c)
       if n[1].kind == nkClosure: result = n[1]
   of nkReturnStmt:
     if n[0].kind in {nkAsgn, nkFastAsgn}:
       # we have a `result = result` expression produced by the closure
       # transform, let's not touch the LHS in order to make the lifting pass
       # correct when `result` is lifted
-      n[0].sons[1] = liftCapturedVars(n[0].sons[1], owner, d, c)
+      n[0][1] = liftCapturedVars(n[0][1], owner, d, c)
     else:
-      n.sons[0] = liftCapturedVars(n[0], owner, d, c)
+      n[0] = liftCapturedVars(n[0], owner, d, c)
   of nkTypeOfExpr:
     result = n
   else:
     if owner.isIterator:
       if nfLL in n.flags:
         # special case 'when nimVm' due to bug #3636:
-        n.sons[1] = liftCapturedVars(n[1], owner, d, c)
+        n[1] = liftCapturedVars(n[1], owner, d, c)
         return
 
     let inContainer = n.kind in {nkObjConstr, nkBracket}
     if inContainer: inc c.inContainer
     for i in 0..<n.len:
-      n.sons[i] = liftCapturedVars(n[i], owner, d, c)
+      n[i] = liftCapturedVars(n[i], owner, d, c)
     if inContainer: dec c.inContainer
 
 # ------------------ old stuff -------------------------------------------
@@ -911,11 +911,10 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode =
         ...
     """
   if liftingHarmful(g.config, owner): return body
-  var L = body.len
-  if not (body.kind == nkForStmt and body[L-2].kind in nkCallKinds):
+  if not (body.kind == nkForStmt and body[^2].kind in nkCallKinds):
     localError(g.config, body.info, "ignored invalid for loop")
     return body
-  var call = body[L-2]
+  var call = body[^2]
 
   result = newNodeI(nkStmtList, body.info)
 
@@ -941,34 +940,34 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode =
   elif op.kind == nkStmtListExpr:
     let closure = op.lastSon
     if closure.kind == nkClosure:
-      call.sons[0] = closure
-      for i in 0 .. op.len-2:
+      call[0] = closure
+      for i in 0..<op.len-1:
         result.add op[i]
 
   var loopBody = newNodeI(nkStmtList, body.info, 3)
   var whileLoop = newNodeI(nkWhileStmt, body.info, 2)
-  whileLoop.sons[0] = newIntTypeNode(1, getSysType(g, body.info, tyBool))
-  whileLoop.sons[1] = loopBody
+  whileLoop[0] = newIntTypeNode(1, getSysType(g, body.info, tyBool))
+  whileLoop[1] = loopBody
   result.add whileLoop
 
   # setup loopBody:
   # gather vars in a tuple:
   var v2 = newNodeI(nkLetSection, body.info)
-  var vpart = newNodeI(if L == 3: nkIdentDefs else: nkVarTuple, body.info)
-  for i in 0 .. L-3:
+  var vpart = newNodeI(if body.len == 3: nkIdentDefs else: nkVarTuple, body.info)
+  for i in 0..<body.len-2:
     if body[i].kind == nkSym:
       body[i].sym.kind = skLet
-    addSon(vpart, body[i])
+    vpart.add body[i]
 
-  addSon(vpart, newNodeI(nkEmpty, body.info)) # no explicit type
+  vpart.add newNodeI(nkEmpty, body.info) # no explicit type
   if not env.isNil:
-    call.sons[0] = makeClosure(g, call.sons[0].sym, env.newSymNode, body.info)
-  addSon(vpart, call)
-  addSon(v2, vpart)
+    call[0] = makeClosure(g, call[0].sym, env.newSymNode, body.info)
+  vpart.add call
+  v2.add vpart
 
-  loopBody.sons[0] = v2
+  loopBody[0] = v2
   var bs = newNodeI(nkBreakState, body.info)
-  bs.addSon(call.sons[0])
+  bs.add call[0]
 
   let ibs = newNodeI(nkIfStmt, body.info)
   let elifBranch = newNodeI(nkElifBranch, body.info)
@@ -980,5 +979,5 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode =
   elifBranch.add(br)
   ibs.add(elifBranch)
 
-  loopBody.sons[1] = ibs
-  loopBody.sons[2] = body[L-1]
+  loopBody[1] = ibs
+  loopBody[2] = body[^1]
diff --git a/compiler/layouter.nim b/compiler/layouter.nim
index 78f6fcfa0..e137ee8a0 100644
--- a/compiler/layouter.nim
+++ b/compiler/layouter.nim
@@ -146,7 +146,7 @@ proc optionalIsGood(em: var Emitter; pos, currentLen: int): bool =
 
 proc lenOfNextTokens(em: Emitter; pos: int): int =
   result = 0
-  for i in 1 ..< em.tokens.len-pos:
+  for i in 1..<em.tokens.len-pos:
     if em.kinds[pos+i] in {ltCrucialNewline, ltSplittingNewline, ltOptionalNewline}: break
     inc result, em.tokens[pos+i].len
 
@@ -570,7 +570,7 @@ proc endsWith(em: Emitter; k: varargs[string]): bool =
   return true
 
 proc rfind(em: Emitter, t: string): int =
-  for i in 1 .. 5:
+  for i in 1..5:
     if em.tokens[^i] == t:
       return i
 
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index 781f023c3..9420d7a48 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -304,11 +304,11 @@ template tokenEndPrevious(tok, pos) =
     tok.offsetB = L.offsetBase + pos
 
 template eatChar(L: var TLexer, t: var TToken, replacementChar: char) =
-  add(t.literal, replacementChar)
+  t.literal.add(replacementChar)
   inc(L.bufpos)
 
 template eatChar(L: var TLexer, t: var TToken) =
-  add(t.literal, L.buf[L.bufpos])
+  t.literal.add(L.buf[L.bufpos])
   inc(L.bufpos)
 
 proc getNumber(L: var TLexer, result: var TToken) =
@@ -317,7 +317,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
     result = 0
     while true:
       if L.buf[pos] in chars:
-        add(tok.literal, L.buf[pos])
+        tok.literal.add(L.buf[pos])
         inc(pos)
         inc(result)
       else:
@@ -328,14 +328,14 @@ proc getNumber(L: var TLexer, result: var TToken) =
             "only single underscores may occur in a token and token may not " &
             "end with an underscore: e.g. '1__1' and '1_' are invalid")
           break
-        add(tok.literal, '_')
+        tok.literal.add('_')
         inc(pos)
     L.bufpos = pos
 
   proc matchChars(L: var TLexer, tok: var TToken, chars: set[char]) =
     var pos = L.bufpos              # use registers for pos, buf
     while L.buf[pos] in chars:
-      add(tok.literal, L.buf[pos])
+      tok.literal.add(L.buf[pos])
       inc(pos)
     L.bufpos = pos
 
@@ -351,12 +351,12 @@ proc getNumber(L: var TLexer, result: var TToken) =
     # We must verify +/- specifically so that we're not past the literal
     if  L.buf[L.bufpos] in {'+', '-'} and
         L.buf[L.bufpos - 1] in {'e', 'E'}:
-      add(t.literal, L.buf[L.bufpos])
+      t.literal.add(L.buf[L.bufpos])
       inc(L.bufpos)
       matchChars(L, t, literalishChars)
     if L.buf[L.bufpos] in {'\'', 'f', 'F', 'd', 'D', 'i', 'I', 'u', 'U'}:
       inc(L.bufpos)
-      add(t.literal, L.buf[L.bufpos])
+      t.literal.add(L.buf[L.bufpos])
       matchChars(L, t, {'0'..'9'})
     L.bufpos = msgPos
     lexMessage(L, msgKind, msg % t.literal)
@@ -687,51 +687,51 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
     if L.config.oldNewlines:
       if tok.tokType == tkCharLit:
         lexMessage(L, errGenerated, "\\n not allowed in character literal")
-      add(tok.literal, L.config.target.tnl)
+      tok.literal.add(L.config.target.tnl)
     else:
-      add(tok.literal, '\L')
+      tok.literal.add('\L')
     inc(L.bufpos)
   of 'p', 'P':
     if tok.tokType == tkCharLit:
       lexMessage(L, errGenerated, "\\p not allowed in character literal")
-    add(tok.literal, L.config.target.tnl)
+    tok.literal.add(L.config.target.tnl)
     inc(L.bufpos)
   of 'r', 'R', 'c', 'C':
-    add(tok.literal, CR)
+    tok.literal.add(CR)
     inc(L.bufpos)
   of 'l', 'L':
-    add(tok.literal, LF)
+    tok.literal.add(LF)
     inc(L.bufpos)
   of 'f', 'F':
-    add(tok.literal, FF)
+    tok.literal.add(FF)
     inc(L.bufpos)
   of 'e', 'E':
-    add(tok.literal, ESC)
+    tok.literal.add(ESC)
     inc(L.bufpos)
   of 'a', 'A':
-    add(tok.literal, BEL)
+    tok.literal.add(BEL)
     inc(L.bufpos)
   of 'b', 'B':
-    add(tok.literal, BACKSPACE)
+    tok.literal.add(BACKSPACE)
     inc(L.bufpos)
   of 'v', 'V':
-    add(tok.literal, VT)
+    tok.literal.add(VT)
     inc(L.bufpos)
   of 't', 'T':
-    add(tok.literal, '\t')
+    tok.literal.add('\t')
     inc(L.bufpos)
   of '\'', '\"':
-    add(tok.literal, L.buf[L.bufpos])
+    tok.literal.add(L.buf[L.bufpos])
     inc(L.bufpos)
   of '\\':
-    add(tok.literal, '\\')
+    tok.literal.add('\\')
     inc(L.bufpos)
   of 'x', 'X':
     inc(L.bufpos)
     var xi = 0
     handleHexChar(L, xi, 1)
     handleHexChar(L, xi, 2)
-    add(tok.literal, chr(xi))
+    tok.literal.add(chr(xi))
   of 'u', 'U':
     if tok.tokType == tkCharLit:
       lexMessage(L, errGenerated, "\\u not allowed in character literal")
@@ -761,14 +761,14 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
       lexMessage(L, warnOctalEscape)
     var xi = 0
     handleDecChars(L, xi)
-    if (xi <= 255): add(tok.literal, chr(xi))
+    if (xi <= 255): tok.literal.add(chr(xi))
     else: lexMessage(L, errGenerated, "invalid character constant")
   else: lexMessage(L, errGenerated, "invalid character constant")
 
 proc newString(s: cstring, len: int): string =
   ## XXX, how come there is no support for this?
   result = newString(len)
-  for i in 0 ..< len:
+  for i in 0..<len:
     result[i] = s[i]
 
 proc handleCRLF(L: var TLexer, pos: int): int =
@@ -815,12 +815,12 @@ proc getString(L: var TLexer, tok: var TToken, mode: StringMode) =
           tokenEndIgnore(tok, pos+2)
           L.bufpos = pos + 3 # skip the three """
           break
-        add(tok.literal, '\"')
+        tok.literal.add('\"')
         inc(pos)
       of CR, LF:
         tokenEndIgnore(tok, pos)
         pos = handleCRLF(L, pos)
-        add(tok.literal, "\n")
+        tok.literal.add("\n")
       of nimlexbase.EndOfFile:
         tokenEndIgnore(tok, pos)
         var line2 = L.lineNumber
@@ -830,7 +830,7 @@ proc getString(L: var TLexer, tok: var TToken, mode: StringMode) =
         L.bufpos = pos
         break
       else:
-        add(tok.literal, L.buf[pos])
+        tok.literal.add(L.buf[pos])
         inc(pos)
   else:
     # ordinary string literal
@@ -841,7 +841,7 @@ proc getString(L: var TLexer, tok: var TToken, mode: StringMode) =
       if c == '\"':
         if mode != normal and L.buf[pos+1] == '\"':
           inc(pos, 2)
-          add(tok.literal, '"')
+          tok.literal.add('"')
         else:
           tokenEndIgnore(tok, pos)
           inc(pos) # skip '"'
@@ -855,7 +855,7 @@ proc getString(L: var TLexer, tok: var TToken, mode: StringMode) =
         getEscapedChar(L, tok)
         pos = L.bufpos
       else:
-        add(tok.literal, c)
+        tok.literal.add(c)
         inc(pos)
     L.bufpos = pos
 
@@ -947,15 +947,14 @@ proc getPrecedence*(tok: TToken, strongSpaces: bool): int =
 
   case tok.tokType
   of tkOpr:
-    let L = tok.ident.s.len
     let relevantChar = tok.ident.s[0]
 
     # arrow like?
-    if L > 1 and tok.ident.s[L-1] == '>' and
-      tok.ident.s[L-2] in {'-', '~', '='}: return considerStrongSpaces(1)
+    if tok.ident.s.len > 1 and tok.ident.s[^1] == '>' and
+      tok.ident.s[^2] in {'-', '~', '='}: return considerStrongSpaces(1)
 
     template considerAsgn(value: untyped) =
-      result = if tok.ident.s[L-1] == '=': 1 else: value
+      result = if tok.ident.s[^1] == '=': 1 else: value
 
     case relevantChar
     of '$', '^': considerAsgn(10)
@@ -1081,7 +1080,7 @@ proc scanComment(L: var TLexer, tok: var TToken) =
     var lastBackslash = -1
     while L.buf[pos] notin {CR, LF, nimlexbase.EndOfFile}:
       if L.buf[pos] == '\\': lastBackslash = pos+1
-      add(tok.literal, L.buf[pos])
+      tok.literal.add(L.buf[pos])
       inc(pos)
     tokenEndIgnore(tok, pos)
     pos = handleCRLF(L, pos)
@@ -1351,7 +1350,7 @@ proc getPrecedence*(ident: PIdent): int =
   initToken(tok)
   tok.ident = ident
   tok.tokType =
-    if tok.ident.id in ord(tokKeywordLow) - ord(tkSymbol) .. ord(tokKeywordHigh) - ord(tkSymbol):
+    if tok.ident.id in ord(tokKeywordLow) - ord(tkSymbol)..ord(tokKeywordHigh) - ord(tkSymbol):
       TTokType(tok.ident.id + ord(tkSymbol))
     else: tkOpr
   getPrecedence(tok, false)
diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim
index 3676aa0f7..a2d952e16 100644
--- a/compiler/liftdestructors.nim
+++ b/compiler/liftdestructors.nim
@@ -34,28 +34,28 @@ proc createTypeBoundOps*(g: ModuleGraph; c: PContext; orig: PType; info: TLineIn
 
 proc at(a, i: PNode, elemType: PType): PNode =
   result = newNodeI(nkBracketExpr, a.info, 2)
-  result.sons[0] = a
-  result.sons[1] = i
+  result[0] = a
+  result[1] = i
   result.typ = elemType
 
 proc fillBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) =
-  for i in 0 ..< t.len:
+  for i in 0..<t.len:
     let lit = lowerings.newIntLit(c.g, x.info, i)
-    fillBody(c, t.sons[i], body, x.at(lit, t.sons[i]), y.at(lit, t.sons[i]))
+    fillBody(c, t[i], body, x.at(lit, t[i]), y.at(lit, t[i]))
 
 proc dotField(x: PNode, f: PSym): PNode =
   result = newNodeI(nkDotExpr, x.info, 2)
   if x.typ.skipTypes(abstractInst).kind == tyVar:
-    result.sons[0] = x.newDeref
+    result[0] = x.newDeref
   else:
-    result.sons[0] = x
-  result.sons[1] = newSymNode(f, x.info)
+    result[0] = x
+  result[1] = newSymNode(f, x.info)
   result.typ = f.typ
 
 proc newAsgnStmt(le, ri: PNode): PNode =
   result = newNodeI(nkAsgn, le.info, 2)
-  result.sons[0] = le
-  result.sons[1] = ri
+  result[0] = le
+  result[1] = ri
 
 proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
   if c.kind != attachedDestructor:
@@ -90,13 +90,12 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode) =
     caseStmt.add(access)
     var emptyBranches = 0
     # copy the branches over, but replace the fields with the for loop body:
-    for i in 1 ..< n.len:
+    for i in 1..<n.len:
       var branch = copyTree(n[i])
-      let L = branch.len
-      branch.sons[L-1] = newNodeI(nkStmtList, c.info)
+      branch[^1] = newNodeI(nkStmtList, c.info)
 
-      fillBodyObj(c, n[i].lastSon, branch.sons[L-1], x, y)
-      if branch.sons[L-1].len == 0: inc emptyBranches
+      fillBodyObj(c, n[i].lastSon, branch[^1], x, y)
+      if branch[^1].len == 0: inc emptyBranches
       caseStmt.add(branch)
     if emptyBranches != n.len-1:
       body.add(caseStmt)
@@ -106,17 +105,17 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode) =
     illFormedAstLocal(n, c.g.config)
 
 proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
-  if t.len > 0 and t.sons[0] != nil:
-    fillBodyObjT(c, skipTypes(t.sons[0], abstractPtrs), body, x, y)
+  if t.len > 0 and t[0] != nil:
+    fillBodyObjT(c, skipTypes(t[0], abstractPtrs), body, x, y)
   fillBodyObj(c, t.n, body, x, y)
 
 proc genAddr(g: ModuleGraph; x: PNode): PNode =
   if x.kind == nkHiddenDeref:
     checkSonsLen(x, 1, g.config)
-    result = x.sons[0]
+    result = x[0]
   else:
     result = newNodeIT(nkHiddenAddr, x.info, makeVarType(x.typ.owner, x.typ))
-    addSon(result, x)
+    result.add x
 
 proc newAsgnCall(g: ModuleGraph; op: PSym; x, y: PNode): PNode =
   #if sfError in op.flags:
@@ -127,12 +126,12 @@ proc newAsgnCall(g: ModuleGraph; op: PSym; x, y: PNode): PNode =
   result.add y
 
 proc newOpCall(op: PSym; x: PNode): PNode =
-  result = newNodeIT(nkCall, x.info, op.typ.sons[0])
+  result = newNodeIT(nkCall, x.info, op.typ[0])
   result.add(newSymNode(op))
   result.add x
 
 proc destructorCall(g: ModuleGraph; op: PSym; x: PNode): PNode =
-  result = newNodeIT(nkCall, x.info, op.typ.sons[0])
+  result = newNodeIT(nkCall, x.info, op.typ[0])
   result.add(newSymNode(op))
   result.add genAddr(g, x)
 
@@ -246,10 +245,10 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
 
 proc addVar(father, v, value: PNode) =
   var vpart = newNodeI(nkIdentDefs, v.info, 3)
-  vpart.sons[0] = v
-  vpart.sons[1] = newNodeI(nkEmpty, v.info)
-  vpart.sons[2] = value
-  addSon(father, vpart)
+  vpart[0] = v
+  vpart[1] = newNodeI(nkEmpty, v.info)
+  vpart[2] = value
+  father.add vpart
 
 proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
   var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.fn, c.info)
@@ -271,8 +270,8 @@ proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode =
   let cmp = genBuiltin(c.g, mLtI, "<", i)
   cmp.add genLen(c.g, dest)
   cmp.typ = getSysType(c.g, c.info, tyBool)
-  result.sons[0] = cmp
-  result.sons[1] = newNodeI(nkStmtList, c.info)
+  result[0] = cmp
+  result[1] = newNodeI(nkStmtList, c.info)
 
 proc genIf(c: var TLiftCtx; cond, action: PNode): PNode =
   result = newTree(nkIfStmt, newTree(nkElifBranch, cond, action))
@@ -306,9 +305,9 @@ proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) =
   let i = declareCounter(c, body, toInt64(firstOrd(c.g.config, t)))
   let whileLoop = genWhileLoop(c, i, x)
   let elemType = t.lastSon
-  fillBody(c, elemType, whileLoop.sons[1], x.at(i, elemType),
+  fillBody(c, elemType, whileLoop[1], x.at(i, elemType),
                                            y.at(i, elemType))
-  addIncStmt(c, whileLoop.sons[1], i)
+  addIncStmt(c, whileLoop[1], i)
   body.add whileLoop
 
 proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
@@ -481,8 +480,8 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
     # have to go through some indirection; we delegate this to the codegen:
     let call = newNodeI(nkCall, c.info, 2)
     call.typ = t
-    call.sons[0] = newSymNode(createMagic(c.g, "deepCopy", mDeepCopy))
-    call.sons[1] = y
+    call[0] = newSymNode(createMagic(c.g, "deepCopy", mDeepCopy))
+    call[1] = y
     body.add newAsgnStmt(x, call)
   elif (optOwnedRefs in c.g.config.globalOptions and
       optRefCheck in c.g.config.options) or c.g.config.selectedGC == gcDestructors:
@@ -587,7 +586,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
       fillBodyObjT(c, t, body, x, y)
   of tyDistinct:
     if not considerUserDefinedOp(c, t, body, x, y):
-      fillBody(c, t.sons[0], body, x, y)
+      fillBody(c, t[0], body, x, y)
   of tyTuple:
     fillBodyTup(c, t, body, x, y)
   of tyVarargs, tyOpenArray:
@@ -659,10 +658,10 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
     fillBody(a, typ, body, newSymNode(dest).newDeref, newSymNode(src))
 
   var n = newNodeI(nkProcDef, info, bodyPos+1)
-  for i in 0 ..< n.len: n.sons[i] = newNodeI(nkEmpty, info)
-  n.sons[namePos] = newSymNode(result)
-  n.sons[paramsPos] = result.typ.n
-  n.sons[bodyPos] = body
+  for i in 0..<n.len: n[i] = newNodeI(nkEmpty, info)
+  n[namePos] = newSymNode(result)
+  n[paramsPos] = result.typ.n
+  n[bodyPos] = body
   result.ast = n
   incl result.flags, sfFromGeneric
   incl result.flags, sfGeneratedOp
@@ -682,7 +681,7 @@ proc patchBody(g: ModuleGraph; c: PContext; n: PNode; info: TLineInfo) =
           internalError(g.config, info, "resolved destructor is generic")
         if t.destructor.magic == mDestroy:
           internalError(g.config, info, "patching mDestroy with mDestroy?")
-        n.sons[0] = newSymNode(t.destructor)
+        n[0] = newSymNode(t.destructor)
   for x in n: patchBody(g, c, x, info)
 
 template inst(field, t) =
diff --git a/compiler/liftlocals.nim b/compiler/liftlocals.nim
index eed0560ab..672dca5d9 100644
--- a/compiler/liftlocals.nim
+++ b/compiler/liftlocals.nim
@@ -30,10 +30,10 @@ proc lookupOrAdd(c: var Ctx; s: PSym; info: TLineInfo): PNode =
   let field = addUniqueField(c.objType, s, c.cache)
   var deref = newNodeI(nkHiddenDeref, info)
   deref.typ = c.objType
-  add(deref, newSymNode(c.partialParam, info))
+  deref.add(newSymNode(c.partialParam, info))
   result = newNodeI(nkDotExpr, info)
-  add(result, deref)
-  add(result, newSymNode(field))
+  result.add(deref)
+  result.add(newSymNode(field))
   result.typ = field.typ
 
 proc liftLocals(n: PNode; i: int; c: var Ctx) =
@@ -44,12 +44,12 @@ proc liftLocals(n: PNode; i: int; c: var Ctx) =
       n[i] = lookupOrAdd(c, it.sym, it.info)
   of procDefs, nkTypeSection: discard
   else:
-    for i in 0 ..< it.safeLen:
+    for i in 0..<it.safeLen:
       liftLocals(it, i, c)
 
 proc lookupParam(params, dest: PNode): PSym =
   if dest.kind != nkIdent: return nil
-  for i in 1 ..< params.len:
+  for i in 1..<params.len:
     if params[i].kind == nkSym and params[i].sym.name.id == dest.ident.id:
       return params[i].sym
 
diff --git a/compiler/linter.nim b/compiler/linter.nim
index 41ee24fa5..07563ddbb 100644
--- a/compiler/linter.nim
+++ b/compiler/linter.nim
@@ -72,10 +72,9 @@ proc beautifyName(s: string, k: TSymKind): string =
 proc differ*(line: string, a, b: int, x: string): string =
   proc substrEq(s: string, pos, last: int, substr: string): bool =
     var i = 0
-    var length = substr.len
-    while i < length and pos+i <= last and s[pos+i] == substr[i]:
+    while i < substr.len and pos+i <= last and s[pos+i] == substr[i]:
       inc i
-    return i == length
+    return i == substr.len
 
   let last = min(b, line.len)
 
diff --git a/compiler/llstream.nim b/compiler/llstream.nim
index ab4e1645c..fffc8db48 100644
--- a/compiler/llstream.nim
+++ b/compiler/llstream.nim
@@ -109,12 +109,12 @@ proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
   var line = newStringOfCap(120)
   var triples = 0
   while readLineFromStdin(if s.s.len == 0: ">>> " else: "... ", line):
-    add(s.s, line)
-    add(s.s, "\n")
+    s.s.add(line)
+    s.s.add("\n")
     inc triples, countTriples(line)
     if not continueLine(line, (triples and 1) == 1): break
   inc(s.lineOffset)
-  result = min(bufLen, len(s.s) - s.rd)
+  result = min(bufLen, s.s.len - s.rd)
   if result > 0:
     copyMem(buf, addr(s.s[s.rd]), result)
     inc(s.rd, result)
@@ -124,7 +124,7 @@ proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int =
   of llsNone:
     result = 0
   of llsString:
-    result = min(bufLen, len(s.s) - s.rd)
+    result = min(bufLen, s.s.len - s.rd)
     if result > 0:
       copyMem(buf, addr(s.s[0 + s.rd]), result)
       inc(s.rd, result)
@@ -139,7 +139,7 @@ proc llStreamReadLine*(s: PLLStream, line: var string): bool =
   of llsNone:
     result = true
   of llsString:
-    while s.rd < len(s.s):
+    while s.rd < s.s.len:
       case s.s[s.rd]
       of '\x0D':
         inc(s.rd)
@@ -149,9 +149,9 @@ proc llStreamReadLine*(s: PLLStream, line: var string): bool =
         inc(s.rd)
         break
       else:
-        add(line, s.s[s.rd])
+        line.add(s.s[s.rd])
         inc(s.rd)
-    result = line.len > 0 or s.rd < len(s.s)
+    result = line.len > 0 or s.rd < s.s.len
   of llsFile:
     result = readLine(s.f, line)
   of llsStdIn:
@@ -162,8 +162,8 @@ proc llStreamWrite*(s: PLLStream, data: string) =
   of llsNone, llsStdIn:
     discard
   of llsString:
-    add(s.s, data)
-    inc(s.wr, len(data))
+    s.s.add(data)
+    inc(s.wr, data.len)
   of llsFile:
     write(s.f, data)
 
@@ -177,7 +177,7 @@ proc llStreamWrite*(s: PLLStream, data: char) =
   of llsNone, llsStdIn:
     discard
   of llsString:
-    add(s.s, data)
+    s.s.add(data)
     inc(s.wr)
   of llsFile:
     c = data
@@ -189,7 +189,7 @@ proc llStreamWrite*(s: PLLStream, buf: pointer, buflen: int) =
     discard
   of llsString:
     if buflen > 0:
-      setLen(s.s, len(s.s) + buflen)
+      setLen(s.s, s.s.len + buflen)
       copyMem(addr(s.s[0 + s.wr]), buf, buflen)
       inc(s.wr, buflen)
   of llsFile:
@@ -204,7 +204,7 @@ proc llStreamReadAll*(s: PLLStream): string =
   of llsString:
     if s.rd == 0: result = s.s
     else: result = substr(s.s, s.rd)
-    s.rd = len(s.s)
+    s.rd = s.s.len
   of llsFile:
     result = newString(bufSize)
     var bytes = readBuffer(s.f, addr(result[0]), bufSize)
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index 57d86c775..8c231212d 100644
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -36,11 +36,11 @@ proc considerQuotedIdent*(c: PContext; n: PNode, origin: PNode = nil): PIdent =
   of nkAccQuoted:
     case n.len
     of 0: handleError(n, origin)
-    of 1: result = considerQuotedIdent(c, n.sons[0], origin)
+    of 1: result = considerQuotedIdent(c, n[0], origin)
     else:
       var id = ""
       for i in 0..<n.len:
-        let x = n.sons[i]
+        let x = n[i]
         case x.kind
         of nkIdent: id.add(x.ident.s)
         of nkSym: id.add(x.sym.name.s)
@@ -49,7 +49,7 @@ proc considerQuotedIdent*(c: PContext; n: PNode, origin: PNode = nil): PIdent =
       result = getIdent(c.cache, id)
   of nkOpenSymChoice, nkClosedSymChoice:
     if n[0].kind == nkSym:
-      result = n.sons[0].sym.name
+      result = n[0].sym.name
     else:
       handleError(n, origin)
   else:
@@ -105,7 +105,7 @@ when declared(echo):
     var i = 0
     for scope in walkScopes(c.currentScope):
       echo "scope ", i
-      for h in 0 .. high(scope.symbols.data):
+      for h in 0..high(scope.symbols.data):
         if scope.symbols.data[h] != nil:
           echo scope.symbols.data[h].name.s
       if i == limit: break
@@ -124,7 +124,7 @@ proc errorSym*(c: PContext, n: PNode): PSym =
   ## creates an error symbol to avoid cascading errors (for IDE support)
   var m = n
   # ensure that 'considerQuotedIdent' can't fail:
-  if m.kind == nkDotExpr: m = m.sons[1]
+  if m.kind == nkDotExpr: m = m[1]
   let ident = if m.kind in {nkIdent, nkSym, nkAccQuoted}:
       considerQuotedIdent(c, m)
     else:
@@ -326,29 +326,29 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
       errorUseQualifier(c, n.info, n.sym)
   of nkDotExpr:
     result = nil
-    var m = qualifiedLookUp(c, n.sons[0], (flags*{checkUndeclared})+{checkModule})
+    var m = qualifiedLookUp(c, n[0], (flags*{checkUndeclared})+{checkModule})
     if m != nil and m.kind == skModule:
       var ident: PIdent = nil
-      if n.sons[1].kind == nkIdent:
-        ident = n.sons[1].ident
-      elif n.sons[1].kind == nkAccQuoted:
-        ident = considerQuotedIdent(c, n.sons[1])
+      if n[1].kind == nkIdent:
+        ident = n[1].ident
+      elif n[1].kind == nkAccQuoted:
+        ident = considerQuotedIdent(c, n[1])
       if ident != nil:
         if m == c.module:
           result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n, c.config)
         else:
           result = strTableGet(m.tab, ident).skipAlias(n, c.config)
         if result == nil and checkUndeclared in flags:
-          fixSpelling(n.sons[1], ident, searchInScopes)
-          errorUndeclaredIdentifier(c, n.sons[1].info, ident.s)
-          result = errorSym(c, n.sons[1])
-      elif n.sons[1].kind == nkSym:
-        result = n.sons[1].sym
+          fixSpelling(n[1], ident, searchInScopes)
+          errorUndeclaredIdentifier(c, n[1].info, ident.s)
+          result = errorSym(c, n[1])
+      elif n[1].kind == nkSym:
+        result = n[1].sym
       elif checkUndeclared in flags and
-           n.sons[1].kind notin {nkOpenSymChoice, nkClosedSymChoice}:
-        localError(c.config, n.sons[1].info, "identifier expected, but got: " &
-                   renderTree(n.sons[1]))
-        result = errorSym(c, n.sons[1])
+           n[1].kind notin {nkOpenSymChoice, nkClosedSymChoice}:
+        localError(c.config, n[1].info, "identifier expected, but got: " &
+                   renderTree(n[1]))
+        result = errorSym(c, n[1])
   else:
     result = nil
   when false:
@@ -372,13 +372,13 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
     o.mode = oimDone
   of nkDotExpr:
     o.mode = oimOtherModule
-    o.m = qualifiedLookUp(c, n.sons[0], {checkUndeclared, checkModule})
+    o.m = qualifiedLookUp(c, n[0], {checkUndeclared, checkModule})
     if o.m != nil and o.m.kind == skModule:
       var ident: PIdent = nil
-      if n.sons[1].kind == nkIdent:
-        ident = n.sons[1].ident
-      elif n.sons[1].kind == nkAccQuoted:
-        ident = considerQuotedIdent(c, n.sons[1], n)
+      if n[1].kind == nkIdent:
+        ident = n[1].ident
+      elif n[1].kind == nkAccQuoted:
+        ident = considerQuotedIdent(c, n[1], n)
       if ident != nil:
         if o.m == c.module:
           # a module may access its private members:
@@ -388,12 +388,12 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
         else:
           result = initIdentIter(o.it, o.m.tab, ident).skipAlias(n, c.config)
       else:
-        noidentError(c.config, n.sons[1], n)
-        result = errorSym(c, n.sons[1])
+        noidentError(c.config, n[1], n)
+        result = errorSym(c, n[1])
   of nkClosedSymChoice, nkOpenSymChoice:
     o.mode = oimSymChoice
     if n[0].kind == nkSym:
-      result = n.sons[0].sym
+      result = n[0].sym
     else:
       o.mode = oimDone
       return nil
@@ -430,8 +430,8 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
   of oimOtherModule:
     result = nextIdentIter(o.it, o.m.tab).skipAlias(n, c.config)
   of oimSymChoice:
-    if o.symChoiceIndex < len(n):
-      result = n.sons[o.symChoiceIndex].sym
+    if o.symChoiceIndex < n.len:
+      result = n[o.symChoiceIndex].sym
       incl(o.inSymChoice, result.id)
       inc o.symChoiceIndex
     elif n.kind == nkOpenSymChoice:
@@ -439,19 +439,19 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
       o.mode = oimSymChoiceLocalLookup
       o.scope = c.currentScope
       result = firstIdentExcluding(o.it, o.scope.symbols,
-                                   n.sons[0].sym.name, o.inSymChoice).skipAlias(n, c.config)
+                                   n[0].sym.name, o.inSymChoice).skipAlias(n, c.config)
       while result == nil:
         o.scope = o.scope.parent
         if o.scope == nil: break
         result = firstIdentExcluding(o.it, o.scope.symbols,
-                                     n.sons[0].sym.name, o.inSymChoice).skipAlias(n, c.config)
+                                     n[0].sym.name, o.inSymChoice).skipAlias(n, c.config)
   of oimSymChoiceLocalLookup:
     result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice).skipAlias(n, c.config)
     while result == nil:
       o.scope = o.scope.parent
       if o.scope == nil: break
       result = firstIdentExcluding(o.it, o.scope.symbols,
-                                   n.sons[0].sym.name, o.inSymChoice).skipAlias(n, c.config)
+                                   n[0].sym.name, o.inSymChoice).skipAlias(n, c.config)
 
   when false:
     if result != nil and result.kind == skStub: loadStub(result)
diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim
index 96afc4828..894efab5c 100644
--- a/compiler/lowerings.nim
+++ b/compiler/lowerings.nim
@@ -16,41 +16,41 @@ import ast, astalgo, types, idents, magicsys, msgs, options, modulegraphs,
   lineinfos
 
 proc newDeref*(n: PNode): PNode {.inline.} =
-  result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
-  addSon(result, n)
+  result = newNodeIT(nkHiddenDeref, n.info, n.typ[0])
+  result.add n
 
 proc newTupleAccess*(g: ModuleGraph; tup: PNode, i: int): PNode =
   if tup.kind == nkHiddenAddr:
     result = newNodeIT(nkHiddenAddr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyLent}))
-    result.addSon(newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyLent}).sons[i]))
-    addSon(result[0], tup[0])
+    result.add newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyLent})[i])
+    result[0].add tup[0]
     var lit = newNodeIT(nkIntLit, tup.info, getSysType(g, tup.info, tyInt))
     lit.intVal = i
-    addSon(result[0], lit)
+    result[0].add lit
   else:
     result = newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(
-                       abstractInst).sons[i])
-    addSon(result, copyTree(tup))
+                       abstractInst)[i])
+    result.add copyTree(tup)
     var lit = newNodeIT(nkIntLit, tup.info, getSysType(g, tup.info, tyInt))
     lit.intVal = i
-    addSon(result, lit)
+    result.add lit
 
 proc addVar*(father, v: PNode) =
   var vpart = newNodeI(nkIdentDefs, v.info, 3)
-  vpart.sons[0] = v
-  vpart.sons[1] = newNodeI(nkEmpty, v.info)
-  vpart.sons[2] = vpart[1]
-  addSon(father, vpart)
+  vpart[0] = v
+  vpart[1] = newNodeI(nkEmpty, v.info)
+  vpart[2] = vpart[1]
+  father.add vpart
 
 proc newAsgnStmt*(le, ri: PNode): PNode =
   result = newNodeI(nkAsgn, le.info, 2)
-  result.sons[0] = le
-  result.sons[1] = ri
+  result[0] = le
+  result[1] = ri
 
 proc newFastAsgnStmt*(le, ri: PNode): PNode =
   result = newNodeI(nkFastAsgn, le.info, 2)
-  result.sons[0] = le
-  result.sons[1] = ri
+  result[0] = le
+  result[1] = ri
 
 proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
   assert n.kind == nkVarTuple
@@ -68,9 +68,9 @@ proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
   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])
-    result.add newAsgnStmt(n.sons[i], newTupleAccess(g, tempAsNode, i))
+  for i in 0..<n.len-2:
+    if n[i].kind == nkSym: v.addVar(n[i])
+    result.add newAsgnStmt(n[i], newTupleAccess(g, tempAsNode, i))
 
 proc evalOnce*(g: ModuleGraph; value: PNode; owner: PSym): PNode =
   ## Turns (value) into (let tmp = value; tmp) so that 'value' can be re-used
@@ -90,10 +90,10 @@ proc evalOnce*(g: ModuleGraph; value: PNode; owner: PSym): PNode =
 
 proc newTupleAccessRaw*(tup: PNode, i: int): PNode =
   result = newNodeI(nkBracketExpr, tup.info)
-  addSon(result, copyTree(tup))
+  result.add copyTree(tup)
   var lit = newNodeI(nkIntLit, tup.info)
   lit.intVal = i
-  addSon(result, lit)
+  result.add lit
 
 proc newTryFinally*(body, final: PNode): PNode =
   result = newTree(nkHiddenTryStmt, body, newTree(nkFinally, final))
@@ -107,31 +107,31 @@ proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
   let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info)
 
   var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
-  vpart.sons[0] = tempAsNode
-  vpart.sons[1] = newNodeI(nkEmpty, value.info)
-  vpart.sons[2] = value
-  addSon(v, vpart)
+  vpart[0] = tempAsNode
+  vpart[1] = newNodeI(nkEmpty, value.info)
+  vpart[2] = value
+  v.add vpart
   result.add(v)
 
-  let lhs = n.sons[0]
-  for i in 0 .. lhs.len-1:
-    result.add newAsgnStmt(lhs.sons[i], newTupleAccessRaw(tempAsNode, i))
+  let lhs = n[0]
+  for i in 0..<lhs.len:
+    result.add newAsgnStmt(lhs[i], newTupleAccessRaw(tempAsNode, i))
 
 proc lowerSwap*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
   result = newNodeI(nkStmtList, n.info)
   # note: cannot use 'skTemp' here cause we really need the copy for the VM :-(
   var temp = newSym(skVar, getIdent(g.cache, genPrefix), owner, n.info, owner.options)
-  temp.typ = n.sons[1].typ
+  temp.typ = n[1].typ
   incl(temp.flags, sfFromGeneric)
 
   var v = newNodeI(nkVarSection, n.info)
   let tempAsNode = newSymNode(temp)
 
   var vpart = newNodeI(nkIdentDefs, v.info, 3)
-  vpart.sons[0] = tempAsNode
-  vpart.sons[1] = newNodeI(nkEmpty, v.info)
-  vpart.sons[2] = n[1]
-  addSon(v, vpart)
+  vpart[0] = tempAsNode
+  vpart[1] = newNodeI(nkEmpty, v.info)
+  vpart[2] = n[1]
+  v.add vpart
 
   result.add(v)
   result.add newFastAsgnStmt(n[1], n[2])
@@ -159,8 +159,8 @@ template fieldCheck {.dirty.} =
 
 proc rawAddField*(obj: PType; field: PSym) =
   assert field.kind == skField
-  field.position = len(obj.n)
-  addSon(obj.n, newSymNode(field))
+  field.position = obj.n.len
+  obj.n.add newSymNode(field)
   propagateToOwner(obj, field.typ)
   fieldCheck()
 
@@ -168,36 +168,36 @@ proc rawIndirectAccess*(a: PNode; field: PSym; info: TLineInfo): PNode =
   # returns a[].field as a node
   assert field.kind == skField
   var deref = newNodeI(nkHiddenDeref, info)
-  deref.typ = a.typ.skipTypes(abstractInst).sons[0]
-  addSon(deref, a)
+  deref.typ = a.typ.skipTypes(abstractInst)[0]
+  deref.add a
   result = newNodeI(nkDotExpr, info)
-  addSon(result, deref)
-  addSon(result, newSymNode(field))
+  result.add deref
+  result.add newSymNode(field)
   result.typ = field.typ
 
 proc rawDirectAccess*(obj, field: PSym): PNode =
   # returns a.field as a node
   assert field.kind == skField
   result = newNodeI(nkDotExpr, field.info)
-  addSon(result, newSymNode obj)
-  addSon(result, newSymNode field)
+  result.add newSymNode(obj)
+  result.add newSymNode(field)
   result.typ = field.typ
 
 proc lookupInRecord(n: PNode, id: int): PSym =
   result = nil
   case n.kind
   of nkRecList:
-    for i in 0 ..< len(n):
-      result = lookupInRecord(n.sons[i], id)
+    for i in 0..<n.len:
+      result = lookupInRecord(n[i], id)
       if result != nil: return
   of nkRecCase:
-    if n.sons[0].kind != nkSym: return
-    result = lookupInRecord(n.sons[0], id)
+    if n[0].kind != nkSym: return
+    result = lookupInRecord(n[0], id)
     if result != nil: return
-    for i in 1 ..< len(n):
-      case n.sons[i].kind
+    for i in 1..<n.len:
+      case n[i].kind
       of nkOfBranch, nkElse:
-        result = lookupInRecord(lastSon(n.sons[i]), id)
+        result = lookupInRecord(lastSon(n[i]), id)
         if result != nil: return
       else: discard
   of nkSym:
@@ -214,8 +214,8 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache) =
   field.typ = t
   assert t.kind != tyTyped
   propagateToOwner(obj, t)
-  field.position = len(obj.n)
-  addSon(obj.n, newSymNode(field))
+  field.position = obj.n.len
+  obj.n.add newSymNode(field)
   fieldCheck()
 
 proc addUniqueField*(obj: PType; s: PSym; cache: IdentCache): PSym {.discardable.} =
@@ -228,45 +228,45 @@ proc addUniqueField*(obj: PType; s: PSym; cache: IdentCache): PSym {.discardable
     field.typ = t
     assert t.kind != tyTyped
     propagateToOwner(obj, t)
-    field.position = len(obj.n)
-    addSon(obj.n, newSymNode(field))
+    field.position = obj.n.len
+    obj.n.add newSymNode(field)
     result = field
 
 proc newDotExpr*(obj, b: PSym): PNode =
   result = newNodeI(nkDotExpr, obj.info)
   let field = lookupInRecord(obj.typ.n, b.id)
   assert field != nil, b.name.s
-  addSon(result, newSymNode(obj))
-  addSon(result, newSymNode(field))
+  result.add newSymNode(obj)
+  result.add newSymNode(field)
   result.typ = field.typ
 
 proc indirectAccess*(a: PNode, b: int, info: TLineInfo): PNode =
   # returns a[].b as a node
   var deref = newNodeI(nkHiddenDeref, info)
-  deref.typ = a.typ.skipTypes(abstractInst).sons[0]
+  deref.typ = a.typ.skipTypes(abstractInst)[0]
   var t = deref.typ.skipTypes(abstractInst)
   var field: PSym
   while true:
     assert t.kind == tyObject
     field = lookupInRecord(t.n, b)
     if field != nil: break
-    t = t.sons[0]
+    t = t[0]
     if t == nil: break
     t = t.skipTypes(skipPtrs)
   #if field == nil:
   #  echo "FIELD ", b
   #  debug deref.typ
   assert field != nil
-  addSon(deref, a)
+  deref.add a
   result = newNodeI(nkDotExpr, info)
-  addSon(result, deref)
-  addSon(result, newSymNode(field))
+  result.add deref
+  result.add newSymNode(field)
   result.typ = field.typ
 
 proc indirectAccess*(a: PNode, b: string, info: TLineInfo; cache: IdentCache): PNode =
   # returns a[].b as a node
   var deref = newNodeI(nkHiddenDeref, info)
-  deref.typ = a.typ.skipTypes(abstractInst).sons[0]
+  deref.typ = a.typ.skipTypes(abstractInst)[0]
   var t = deref.typ.skipTypes(abstractInst)
   var field: PSym
   let bb = getIdent(cache, b)
@@ -274,17 +274,17 @@ proc indirectAccess*(a: PNode, b: string, info: TLineInfo; cache: IdentCache): P
     assert t.kind == tyObject
     field = getSymFromList(t.n, bb)
     if field != nil: break
-    t = t.sons[0]
+    t = t[0]
     if t == nil: break
     t = t.skipTypes(skipPtrs)
   #if field == nil:
   #  echo "FIELD ", b
   #  debug deref.typ
   assert field != nil
-  addSon(deref, a)
+  deref.add a
   result = newNodeI(nkDotExpr, info)
-  addSon(result, deref)
-  addSon(result, newSymNode(field))
+  result.add deref
+  result.add newSymNode(field)
   result.typ = field.typ
 
 proc getFieldFromObj*(t: PType; v: PSym): PSym =
@@ -294,7 +294,7 @@ proc getFieldFromObj*(t: PType; v: PSym): PSym =
     assert t.kind == tyObject
     result = lookupInRecord(t.n, v.id)
     if result != nil: break
-    t = t.sons[0]
+    t = t[0]
     if t == nil: break
     t = t.skipTypes(skipPtrs)
 
@@ -307,13 +307,13 @@ proc indirectAccess*(a, b: PSym, info: TLineInfo): PNode =
 
 proc genAddrOf*(n: PNode): PNode =
   result = newNodeI(nkAddr, n.info, 1)
-  result.sons[0] = n
+  result[0] = n
   result.typ = newType(tyPtr, n.typ.owner)
   result.typ.rawAddSon(n.typ)
 
 proc genDeref*(n: PNode; k = nkHiddenDeref): PNode =
   result = newNodeIT(k, n.info,
-                     n.typ.skipTypes(abstractInst).sons[0])
+                     n.typ.skipTypes(abstractInst)[0])
   result.add n
 
 proc callCodegenProc*(g: ModuleGraph; name: string;
@@ -329,9 +329,9 @@ proc callCodegenProc*(g: ModuleGraph; name: string;
     if arg2 != nil: result.add arg2
     if arg3 != nil: result.add arg3
     if optionalArgs != nil:
-      for i in 1..optionalArgs.len-3:
+      for i in 1..<optionalArgs.len-2:
         result.add optionalArgs[i]
-    result.typ = sym.typ.sons[0]
+    result.typ = sym.typ[0]
 
 proc newIntLit*(g: ModuleGraph; info: TLineInfo; value: BiggestInt): PNode =
   result = nkIntLit.newIntNode(value)
@@ -343,8 +343,8 @@ proc genHigh*(g: ModuleGraph; n: PNode): PNode =
   else:
     result = newNodeI(nkCall, n.info, 2)
     result.typ = getSysType(g, n.info, tyInt)
-    result.sons[0] = newSymNode(getSysMagic(g, n.info, "high", mHigh))
-    result.sons[1] = n
+    result[0] = newSymNode(getSysMagic(g, n.info, "high", mHigh))
+    result[1] = n
 
 proc genLen*(g: ModuleGraph; n: PNode): PNode =
   if skipTypes(n.typ, abstractVar).kind == tyArray:
@@ -352,8 +352,8 @@ proc genLen*(g: ModuleGraph; n: PNode): PNode =
   else:
     result = newNodeI(nkCall, n.info, 2)
     result.typ = getSysType(g, n.info, tyInt)
-    result.sons[0] = newSymNode(getSysMagic(g, n.info, "len", mLengthSeq))
-    result.sons[1] = n
+    result[0] = newSymNode(getSysMagic(g, n.info, "len", mLengthSeq))
+    result[1] = n
 
 proc hoistExpr*(varSection, expr: PNode, name: PIdent, owner: PSym): PSym =
   result = newSym(skLet, name, owner, varSection.info, owner.options)
@@ -361,8 +361,8 @@ proc hoistExpr*(varSection, expr: PNode, name: PIdent, owner: PSym): PSym =
   result.typ = expr.typ
 
   var varDef = newNodeI(nkIdentDefs, varSection.info, 3)
-  varDef.sons[0] = newSymNode(result)
-  varDef.sons[1] = newNodeI(nkEmpty, varSection.info)
-  varDef.sons[2] = expr
+  varDef[0] = newSymNode(result)
+  varDef[1] = newNodeI(nkEmpty, varSection.info)
+  varDef[2] = expr
 
   varSection.add varDef
diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim
index 38240061f..73eacc2d6 100644
--- a/compiler/magicsys.nim
+++ b/compiler/magicsys.nim
@@ -40,7 +40,7 @@ proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSy
   while r != nil:
     if r.magic == m:
       # prefer the tyInt variant:
-      if r.typ.sons[0] != nil and r.typ.sons[0].kind == tyInt: return r
+      if r.typ[0] != nil and r.typ[0].kind == tyInt: return r
       result = r
     r = nextIdentIter(ti, g.systemModule.tab)
   if result != nil: return result
@@ -123,7 +123,7 @@ proc addSonSkipIntLit*(father, son: PType) =
   when not defined(nimNoNilSeqs):
     if isNil(father.sons): father.sons = @[]
   let s = son.skipIntLit
-  add(father.sons, s)
+  father.sons.add(s)
   propagateToOwner(father, s)
 
 proc setIntLitType*(g: ModuleGraph; result: PNode) =
diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim
index eedb22084..0c8a4628e 100644
--- a/compiler/modulepaths.nim
+++ b/compiler/modulepaths.nim
@@ -139,7 +139,7 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string =
       result.add modname
   of nkPrefix:
     when false:
-      if n.sons[0].kind == nkIdent and n.sons[0].ident.s == "$":
+      if n[0].kind == nkIdent and n[0].ident.s == "$":
         result = lookupPackage(n[1], nil)
       else:
         discard
@@ -149,7 +149,7 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string =
     localError(conf, n.info, warnDeprecated, "using '.' instead of '/' in import paths is deprecated")
     result = renderTree(n, {renderNoComments}).replace(".", "/")
   of nkImportAs:
-    result = getModuleName(conf, n.sons[0])
+    result = getModuleName(conf, n[0])
   else:
     localError(conf, n.info, "invalid module name: '$1'" % n.renderTree)
     result = ""
diff --git a/compiler/modules.nim b/compiler/modules.nim
index 02b4d8ac4..174d2117c 100644
--- a/compiler/modules.nim
+++ b/compiler/modules.nim
@@ -93,7 +93,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): P
       if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil)
     graph.markClientsDirty(fileIdx)
 
-proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym {.procvar.} =
+proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym =
   # this is called by the semantic checking phase
   assert graph.config != nil
   result = compileModule(graph, fileIdx, {})
@@ -108,7 +108,7 @@ proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym {.proc
     if s.owner.id == graph.config.mainPackageId or isDefined(graph.config, "booting"): graph.config.mainPackageNotes
     else: graph.config.foreignPackageNotes
 
-proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode {.procvar.} =
+proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode =
   result = syntaxes.parseFile(fileIdx, graph.cache, graph.config)
   graph.addDep(s, fileIdx)
   graph.addIncludeDep(s.position.FileIndex, fileIdx)
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 1264133a9..24865af2c 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -26,13 +26,13 @@ proc makeCString*(s: string): Rope =
   const MaxLineLength = 64
   result = nil
   var res = newStringOfCap(int(s.len.toFloat * 1.1) + 1)
-  add(res, "\"")
-  for i in 0 ..< len(s):
+  res.add("\"")
+  for i in 0..<s.len:
     if (i + 1) mod MaxLineLength == 0:
-      add(res, "\"\L\"")
+      res.add("\"\L\"")
     toCChar(s[i], res)
-  add(res, '\"')
-  add(result, rope(res))
+  res.add('\"')
+  result.add(rope(res))
 
 
 proc newFileInfo(fullPath: AbsoluteFile, projPath: RelativeFile): TFileInfo =
@@ -152,12 +152,11 @@ proc pushInfoContext*(conf: ConfigRef; info: TLineInfo; detail: string = "") =
   conf.m.msgContext.add((info, detail))
 
 proc popInfoContext*(conf: ConfigRef) =
-  setLen(conf.m.msgContext, len(conf.m.msgContext) - 1)
+  setLen(conf.m.msgContext, conf.m.msgContext.len - 1)
 
 proc getInfoContext*(conf: ConfigRef; index: int): TLineInfo =
-  let L = conf.m.msgContext.len
-  let i = if index < 0: L + index else: index
-  if i >=% L: result = unknownLineInfo()
+  let i = if index < 0: conf.m.msgContext.len + index else: index
+  if i >=% conf.m.msgContext.len: result = unknownLineInfo()
   else: result = conf.m.msgContext[i].info
 
 const
@@ -333,7 +332,7 @@ proc getMessageStr(msg: TMsgKind, arg: string): string =
 type
   TErrorHandling = enum doNothing, doAbort, doRaise
 
-proc log*(s: string) {.procvar.} =
+proc log*(s: string) =
   var f: File
   if open(f, getHomeDir() / "nimsuggest.log", fmAppend):
     f.writeLine(s)
@@ -374,7 +373,7 @@ proc writeContext(conf: ConfigRef; lastinfo: TLineInfo) =
   const instantiationFrom = "template/generic instantiation from here"
   const instantiationOfFrom = "template/generic instantiation of `$1` from here"
   var info = lastinfo
-  for i in 0 ..< len(conf.m.msgContext):
+  for i in 0..<conf.m.msgContext.len:
     let context = conf.m.msgContext[i]
     if context.info != lastinfo and context.info != info:
       if conf.structuredErrorHook != nil:
diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim
index 9916f2461..9ef529ff3 100644
--- a/compiler/nimblecmd.nim
+++ b/compiler/nimblecmd.nim
@@ -48,7 +48,7 @@ proc `<`*(ver: Version, ver2: Version): bool =
   # Handling for normal versions such as "0.1.0" or "1.0".
   var sVer = string(ver).split('.')
   var sVer2 = string(ver2).split('.')
-  for i in 0..max(sVer.len, sVer2.len)-1:
+  for i in 0..<max(sVer.len, sVer2.len):
     var sVerI = 0
     if i < sVer.len:
       discard parseInt(sVer[i], sVerI)
@@ -82,7 +82,7 @@ proc getPathVersion*(p: string): tuple[name, version: string] =
       result.name = p
       return
 
-  result.name = p[0 .. sepIdx - 1]
+  result.name = p[0..sepIdx - 1]
   result.version = p.substr(sepIdx + 1)
 
 proc addPackage(conf: ConfigRef; packages: StringTableRef, p: string; info: TLineInfo) =
diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim
index 63cad46af..0818ddd0d 100644
--- a/compiler/nimconf.nim
+++ b/compiler/nimconf.nim
@@ -114,7 +114,7 @@ proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef; condStack
   ppGetTok(L, tok)            # skip @
   case whichKeyword(tok.ident)
   of wIf:
-    setLen(condStack, len(condStack) + 1)
+    setLen(condStack, condStack.len + 1)
     let res = evalppIf(L, tok, config)
     condStack[high(condStack)] = res
     if not res: jumpToDirective(L, tok, jdElseEndif, config, condStack)
@@ -168,38 +168,38 @@ proc parseAssignment(L: var TLexer, tok: var TToken;
   confTok(L, tok, config, condStack)             # skip symbol
   var val = ""
   while tok.tokType == tkDot:
-    add(s, '.')
+    s.add('.')
     confTok(L, tok, config, condStack)
     checkSymbol(L, tok)
-    add(s, $tok)
+    s.add($tok)
     confTok(L, tok, config, condStack)
   if tok.tokType == tkBracketLe:
     # BUGFIX: val, not s!
     confTok(L, tok, config, condStack)
     checkSymbol(L, tok)
-    add(val, '[')
-    add(val, $tok)
+    val.add('[')
+    val.add($tok)
     confTok(L, tok, config, condStack)
     if tok.tokType == tkBracketRi: confTok(L, tok, config, condStack)
     else: lexMessage(L, errGenerated, "expected closing ']'")
-    add(val, ']')
+    val.add(']')
   let percent = tok.ident != nil and tok.ident.s == "%="
   if tok.tokType in {tkColon, tkEquals} or percent:
-    if len(val) > 0: add(val, ':')
+    if val.len > 0: val.add(':')
     confTok(L, tok, config, condStack)           # skip ':' or '=' or '%'
     checkSymbol(L, tok)
-    add(val, $tok)
+    val.add($tok)
     confTok(L, tok, config, condStack)           # skip symbol
     if tok.tokType in {tkColon, tkEquals}:
-      add(val, $tok) # add the :
+      val.add($tok) # add the :
       confTok(L, tok, config, condStack)           # skip symbol
       checkSymbol(L, tok)
-      add(val, $tok) # add the token after it
+      val.add($tok) # add the token after it
       confTok(L, tok, config, condStack)           # skip symbol
     while tok.ident != nil and tok.ident.s == "&":
       confTok(L, tok, config, condStack)
       checkSymbol(L, tok)
-      add(val, $tok)
+      val.add($tok)
       confTok(L, tok, config, condStack)
   if percent:
     processSwitch(s, strtabs.`%`(val, config.configVars,
@@ -221,7 +221,7 @@ proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache;
     var condStack: seq[bool] = @[]
     confTok(L, tok, config, condStack)           # read in the first token
     while tok.tokType != tkEof: parseAssignment(L, tok, config, condStack)
-    if len(condStack) > 0: lexMessage(L, errGenerated, "expected @end")
+    if condStack.len > 0: lexMessage(L, errGenerated, "expected @end")
     closeLexer(L)
     return true
 
@@ -245,7 +245,7 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef) =
   template readConfigFile(path) =
     let configPath = path
     if readConfigFile(configPath, cache, conf):
-      add(configFiles, configPath)
+      configFiles.add(configPath)
 
   if optSkipSystemConfigFile notin conf.globalOptions:
     readConfigFile(getSystemConfigPath(conf, cfg))
diff --git a/compiler/nimlexbase.nim b/compiler/nimlexbase.nim
index 214147a2b..e3e8f1dbb 100644
--- a/compiler/nimlexbase.nim
+++ b/compiler/nimlexbase.nim
@@ -157,7 +157,7 @@ proc getCurrentLine(L: TBaseLexer, marker: bool = true): string =
   result = ""
   var i = L.lineStart
   while not (L.buf[i] in {CR, LF, EndOfFile}):
-    add(result, L.buf[i])
+    result.add(L.buf[i])
     inc(i)
   result.add("\n")
   if marker:
diff --git a/compiler/nimsets.nim b/compiler/nimsets.nim
index 5ae7ef590..3876a114e 100644
--- a/compiler/nimsets.nim
+++ b/compiler/nimsets.nim
@@ -17,13 +17,13 @@ proc inSet*(s: PNode, elem: PNode): bool =
   if s.kind != nkCurly:
     #internalError(s.info, "inSet")
     return false
-  for i in 0 ..< len(s):
-    if s.sons[i].kind == nkRange:
-      if leValue(s.sons[i].sons[0], elem) and
-          leValue(elem, s.sons[i].sons[1]):
+  for i in 0..<s.len:
+    if s[i].kind == nkRange:
+      if leValue(s[i][0], elem) and
+          leValue(elem, s[i][1]):
         return true
     else:
-      if sameValue(s.sons[i], elem):
+      if sameValue(s[i], elem):
         return true
   result = false
 
@@ -31,13 +31,13 @@ proc overlap*(a, b: PNode): bool =
   if a.kind == nkRange:
     if b.kind == nkRange:
       # X..Y and C..D overlap iff (X <= D and C <= Y)
-      result = leValue(a.sons[0], b.sons[1]) and
-               leValue(b.sons[0], a.sons[1])
+      result = leValue(a[0], b[1]) and
+               leValue(b[0], a[1])
     else:
-      result = leValue(a.sons[0], b) and leValue(b, a.sons[1])
+      result = leValue(a[0], b) and leValue(b, a[1])
   else:
     if b.kind == nkRange:
-      result = leValue(b.sons[0], a) and leValue(a, b.sons[1])
+      result = leValue(b[0], a) and leValue(a, b[1])
     else:
       result = sameValue(a, b)
 
@@ -47,61 +47,61 @@ proc someInSet*(s: PNode, a, b: PNode): bool =
   if s.kind != nkCurly:
     #internalError(s.info, "SomeInSet")
     return false
-  for i in 0 ..< len(s):
-    if s.sons[i].kind == nkRange:
-      if leValue(s.sons[i].sons[0], b) and leValue(b, s.sons[i].sons[1]) or
-          leValue(s.sons[i].sons[0], a) and leValue(a, s.sons[i].sons[1]):
+  for i in 0..<s.len:
+    if s[i].kind == nkRange:
+      if leValue(s[i][0], b) and leValue(b, s[i][1]) or
+          leValue(s[i][0], a) and leValue(a, s[i][1]):
         return true
     else:
       # a <= elem <= b
-      if leValue(a, s.sons[i]) and leValue(s.sons[i], b):
+      if leValue(a, s[i]) and leValue(s[i], b):
         return true
   result = false
 
 proc toBitSet*(conf: ConfigRef; s: PNode, b: var TBitSet) =
   var first, j: Int128
-  first = firstOrd(conf, s.typ.sons[0])
+  first = firstOrd(conf, s.typ[0])
   bitSetInit(b, int(getSize(conf, s.typ)))
-  for i in 0 ..< len(s):
-    if s.sons[i].kind == nkRange:
-      j = getOrdValue(s.sons[i].sons[0], first)
-      while j <= getOrdValue(s.sons[i].sons[1], first):
+  for i in 0..<s.len:
+    if s[i].kind == nkRange:
+      j = getOrdValue(s[i][0], first)
+      while j <= getOrdValue(s[i][1], first):
         bitSetIncl(b, toInt64(j - first))
         inc(j)
     else:
-      bitSetIncl(b, toInt64(getOrdValue(s.sons[i]) - first))
+      bitSetIncl(b, toInt64(getOrdValue(s[i]) - first))
 
 proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): PNode =
   var
     a, b, e, first: BiggestInt # a, b are interval borders
     elemType: PType
     n: PNode
-  elemType = settype.sons[0]
+  elemType = settype[0]
   first = firstOrd(conf, elemType).toInt64
   result = newNodeI(nkCurly, info)
   result.typ = settype
   result.info = info
   e = 0
-  while e < len(s) * ElemSize:
+  while e < s.len * ElemSize:
     if bitSetIn(s, e):
       a = e
       b = e
       while true:
         inc(b)
-        if (b >= len(s) * ElemSize) or not bitSetIn(s, b): break
+        if (b >= s.len * ElemSize) or not bitSetIn(s, b): break
       dec(b)
       let aa = newIntTypeNode(a + first, elemType)
       aa.info = info
       if a == b:
-        addSon(result, aa)
+        result.add aa
       else:
         n = newNodeI(nkRange, info)
         n.typ = elemType
-        addSon(n, aa)
+        n.add aa
         let bb = newIntTypeNode(b + first, elemType)
         bb.info = info
-        addSon(n, bb)
-        addSon(result, n)
+        n.add bb
+        result.add n
       e = b
     inc(e)
 
@@ -132,7 +132,7 @@ proc equalSets*(conf: ConfigRef; a, b: PNode): bool =
 proc complement*(conf: ConfigRef; a: PNode): PNode =
   var x: TBitSet
   toBitSet(conf, a, x)
-  for i in 0 .. high(x): x[i] = not x[i]
+  for i in 0..high(x): x[i] = not x[i]
   result = toTreeSet(conf, x, a.typ, a.info)
 
 proc deduplicate*(conf: ConfigRef; a: PNode): PNode =
@@ -149,8 +149,8 @@ proc setHasRange*(s: PNode): bool =
   assert s.kind == nkCurly
   if s.kind != nkCurly:
     return false
-  for i in 0 ..< len(s):
-    if s.sons[i].kind == nkRange:
+  for i in 0..<s.len:
+    if s[i].kind == nkRange:
       return true
   result = false
 
diff --git a/compiler/options.nim b/compiler/options.nim
index f096f22e0..561403077 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -537,15 +537,15 @@ proc shortenDir*(conf: ConfigRef; dir: string): string {.
   ## returns the interesting part of a dir
   var prefix = conf.projectPath.string & DirSep
   if startsWith(dir, prefix):
-    return substr(dir, len(prefix))
+    return substr(dir, prefix.len)
   prefix = getPrefixDir(conf).string & DirSep
   if startsWith(dir, prefix):
-    return substr(dir, len(prefix))
+    return substr(dir, prefix.len)
   result = dir
 
 proc removeTrailingDirSep*(path: string): string =
-  if (len(path) > 0) and (path[len(path) - 1] == DirSep):
-    result = substr(path, 0, len(path) - 2)
+  if (path.len > 0) and (path[^1] == DirSep):
+    result = substr(path, 0, path.len - 2)
   else:
     result = path
 
@@ -643,7 +643,7 @@ template patchModule(conf: ConfigRef) {.dirty.} =
       let ov = conf.moduleOverrides[key]
       if ov.len > 0: result = AbsoluteFile(ov)
 
-proc findFile*(conf: ConfigRef; f: string; suppressStdlib = false): AbsoluteFile {.procvar.} =
+proc findFile*(conf: ConfigRef; f: string; suppressStdlib = false): AbsoluteFile =
   if f.isAbsolute:
     result = if f.existsFile: AbsoluteFile(f) else: AbsoluteFile""
   else:
diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim
index 78ba68ae6..486f8ff54 100644
--- a/compiler/parampatterns.nim
+++ b/compiler/parampatterns.nim
@@ -46,7 +46,7 @@ proc patternError(n: PNode; conf: ConfigRef) =
   localError(conf, n.info, "illformed AST: " & renderTree(n, {renderNoComments}))
 
 proc add(code: var TPatternCode, op: TOpcode) {.inline.} =
-  add(code, chr(ord(op)))
+  code.add chr(ord(op))
 
 proc whichAlias*(p: PSym): TAliasRequest =
   if p.constraint != nil:
@@ -57,29 +57,29 @@ proc whichAlias*(p: PSym): TAliasRequest =
 proc compileConstraints(p: PNode, result: var TPatternCode; conf: ConfigRef) =
   case p.kind
   of nkCallKinds:
-    if p.sons[0].kind != nkIdent:
-      patternError(p.sons[0], conf)
+    if p[0].kind != nkIdent:
+      patternError(p[0], conf)
       return
-    let op = p.sons[0].ident
+    let op = p[0].ident
     if p.len == 3:
       if op.s == "|" or op.id == ord(wOr):
-        compileConstraints(p.sons[1], result, conf)
-        compileConstraints(p.sons[2], result, conf)
+        compileConstraints(p[1], result, conf)
+        compileConstraints(p[2], result, conf)
         result.add(ppOr)
       elif op.s == "&" or op.id == ord(wAnd):
-        compileConstraints(p.sons[1], result, conf)
-        compileConstraints(p.sons[2], result, conf)
+        compileConstraints(p[1], result, conf)
+        compileConstraints(p[2], result, conf)
         result.add(ppAnd)
       else:
         patternError(p, conf)
     elif p.len == 2 and (op.s == "~" or op.id == ord(wNot)):
-      compileConstraints(p.sons[1], result, conf)
+      compileConstraints(p[1], result, conf)
       result.add(ppNot)
     else:
       patternError(p, conf)
   of nkAccQuoted, nkPar:
     if p.len == 1:
-      compileConstraints(p.sons[0], result, conf)
+      compileConstraints(p[0], result, conf)
     else:
       patternError(p, conf)
   of nkIdent:
@@ -138,7 +138,7 @@ proc checkForSideEffects*(n: PNode): TSideEffectAnalysis =
   case n.kind
   of nkCallKinds:
     # only calls can produce side effects:
-    let op = n.sons[0]
+    let op = n[0]
     if op.kind == nkSym and isRoutine(op.sym):
       let s = op.sym
       if sfSideEffect in s.flags:
@@ -152,8 +152,8 @@ proc checkForSideEffects*(n: PNode): TSideEffectAnalysis =
       # indirect call: assume side effect:
       return seSideEffect
     # we need to check n[0] too: (FwithSideEffectButReturnsProcWithout)(args)
-    for i in 0 ..< n.len:
-      let ret = checkForSideEffects(n.sons[i])
+    for i in 0..<n.len:
+      let ret = checkForSideEffects(n[i])
       if ret == seSideEffect: return ret
       elif ret == seUnknown and result == seNoSideEffect:
         result = seUnknown
@@ -163,8 +163,8 @@ proc checkForSideEffects*(n: PNode): TSideEffectAnalysis =
   else:
     # assume no side effect:
     result = seNoSideEffect
-    for i in 0 ..< n.len:
-      let ret = checkForSideEffects(n.sons[i])
+    for i in 0..<n.len:
+      let ret = checkForSideEffects(n[i])
       if ret == seSideEffect: return ret
       elif ret == seUnknown and result == seNoSideEffect:
         result = seUnknown
@@ -232,33 +232,33 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
       let t = n.sym.typ.skipTypes({tyTypeDesc})
       if t.kind == tyVar: result = arStrange
   of nkDotExpr:
-    let t = skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc})
+    let t = skipTypes(n[0].typ, abstractInst-{tyTypeDesc})
     if t.kind in {tyVar, tySink, tyPtr, tyRef}:
       result = arLValue
     elif isUnsafeAddr and t.kind == tyLent:
       result = arLValue
     else:
-      result = isAssignable(owner, n.sons[0], isUnsafeAddr)
+      result = isAssignable(owner, n[0], isUnsafeAddr)
     if result != arNone and n[1].kind == nkSym and
         sfDiscriminant in n[1].sym.flags:
       result = arDiscriminant
   of nkBracketExpr:
-    let t = skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc})
+    let t = skipTypes(n[0].typ, abstractInst-{tyTypeDesc})
     if t.kind in {tyVar, tySink, tyPtr, tyRef}:
       result = arLValue
     elif isUnsafeAddr and t.kind == tyLent:
       result = arLValue
     else:
-      result = isAssignable(owner, n.sons[0], isUnsafeAddr)
+      result = isAssignable(owner, n[0], isUnsafeAddr)
   of nkHiddenStdConv, nkHiddenSubConv, nkConv:
     # Object and tuple conversions are still addressable, so we skip them
     # XXX why is 'tyOpenArray' allowed here?
     if skipTypes(n.typ, abstractPtrs-{tyTypeDesc}).kind in
         {tyOpenArray, tyTuple, tyObject}:
-      result = isAssignable(owner, n.sons[1], isUnsafeAddr)
-    elif compareTypes(n.typ, n.sons[1].typ, dcEqIgnoreDistinct):
+      result = isAssignable(owner, n[1], isUnsafeAddr)
+    elif compareTypes(n.typ, n[1].typ, dcEqIgnoreDistinct):
       # types that are equal modulo distinction preserve l-value:
-      result = isAssignable(owner, n.sons[1], isUnsafeAddr)
+      result = isAssignable(owner, n[1], isUnsafeAddr)
   of nkHiddenDeref:
     if isUnsafeAddr and n[0].typ.kind == tyLent: result = arLValue
     elif n[0].typ.kind == tyLent: result = arDiscriminant
@@ -266,11 +266,11 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
   of nkDerefExpr, nkHiddenAddr:
     result = arLValue
   of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
-    result = isAssignable(owner, n.sons[0], isUnsafeAddr)
+    result = isAssignable(owner, n[0], isUnsafeAddr)
   of nkCallKinds:
     # builtin slice keeps lvalue-ness:
     if getMagic(n) in {mArrGet, mSlice}:
-      result = isAssignable(owner, n.sons[1], isUnsafeAddr)
+      result = isAssignable(owner, n[1], isUnsafeAddr)
     elif n.typ != nil and n.typ.kind == tyVar:
       result = arLValue
     elif isUnsafeAddr and n.typ != nil and n.typ.kind == tyLent:
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 712997fa5..15f2187ed 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -165,11 +165,11 @@ proc rawSkipComment(p: var TParser, node: PNode) =
         if node.comment == nil: node.comment = ""
       when defined(nimpretty):
         if p.tok.commentOffsetB > p.tok.commentOffsetA:
-          add node.comment, fileSection(p.lex.config, p.lex.fileIdx, p.tok.commentOffsetA, p.tok.commentOffsetB)
+          node.comment.add fileSection(p.lex.config, p.lex.fileIdx, p.tok.commentOffsetA, p.tok.commentOffsetB)
         else:
-          add node.comment, p.tok.literal
+          node.comment.add p.tok.literal
       else:
-        add(node.comment, p.tok.literal)
+        node.comment.add  p.tok.literal
     else:
       parMessage(p, errInternal, "skipComment")
     getTok(p)
@@ -261,7 +261,7 @@ proc isSigilLike(tok: TToken): bool {.inline.} =
 proc isRightAssociative(tok: TToken): bool {.inline.} =
   ## Determines whether the token is right assocative.
   result = tok.tokType == tkOpr and tok.ident.s[0] == '^'
-  # or (let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>'))
+  # or (tok.ident.s.len > 1 and tok.ident.s[^1] == '>')
 
 proc isOperator(tok: TToken): bool =
   ## Determines if the given token is an operator type token.
@@ -376,14 +376,14 @@ proc colonOrEquals(p: var TParser, a: PNode): PNode =
     getTok(p)
     newlineWasSplitting(p)
     #optInd(p, result)
-    addSon(result, a)
-    addSon(result, parseExpr(p))
+    result.add(a)
+    result.add(parseExpr(p))
   elif p.tok.tokType == tkEquals:
     result = newNodeP(nkExprEqExpr, p)
     getTok(p)
     #optInd(p, result)
-    addSon(result, a)
-    addSon(result, parseExpr(p))
+    result.add(a)
+    result.add(parseExpr(p))
   else:
     result = a
 
@@ -404,7 +404,7 @@ proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
   # progress guaranteed
   while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof):
     var a = parseExpr(p)
-    addSon(result, a)
+    result.add(a)
     if p.tok.tokType != tkComma: break
     getTok(p)
     optInd(p, a)
@@ -419,7 +419,7 @@ proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) =
   # progress guaranteed
   while p.tok.tokType != endTok and p.tok.tokType != tkEof:
     var a = exprColonEqExpr(p)
-    addSon(result, a)
+    result.add(a)
     if p.tok.tokType != tkComma: break
     getTok(p)
     # (1,) produces a tuple expression
@@ -442,8 +442,8 @@ proc dotExpr(p: var TParser, a: PNode): PNode =
   getTok(p)
   result = newNodeI(nkDotExpr, info)
   optInd(p, result)
-  addSon(result, a)
-  addSon(result, parseSymbol(p, smAfterDot))
+  result.add(a)
+  result.add(parseSymbol(p, smAfterDot))
   if p.tok.tokType == tkBracketLeColon and p.tok.strongSpaceA <= 0:
     var x = newNodeI(nkBracketExpr, p.parLineInfo)
     # rewrite 'x.y[:z]()' to 'y[z](x)'
@@ -475,7 +475,7 @@ proc setOrTableConstr(p: var TParser): PNode =
     while p.tok.tokType notin {tkCurlyRi, tkEof}:
       var a = exprColonEqExpr(p)
       if a.kind == nkExprColonExpr: result.kind = nkTableConstr
-      addSon(result, a)
+      result.add(a)
       if p.tok.tokType != tkComma: break
       getTok(p)
       skipComment(p, a)
@@ -488,12 +488,12 @@ proc parseCast(p: var TParser): PNode =
   getTok(p)
   eat(p, tkBracketLe)
   optInd(p, result)
-  addSon(result, parseTypeDesc(p))
+  result.add(parseTypeDesc(p))
   optPar(p)
   eat(p, tkBracketRi)
   eat(p, tkParLe)
   optInd(p, result)
-  addSon(result, parseExpr(p))
+  result.add(parseExpr(p))
   optPar(p)
   eat(p, tkParRi)
 
@@ -508,13 +508,13 @@ proc parseGStrLit(p: var TParser, a: PNode): PNode =
   case p.tok.tokType
   of tkGStrLit:
     result = newNodeP(nkCallStrLit, p)
-    addSon(result, a)
-    addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p))
+    result.add(a)
+    result.add(newStrNodeP(nkRStrLit, p.tok.literal, p))
     getTok(p)
   of tkGTripleStrLit:
     result = newNodeP(nkCallStrLit, p)
-    addSon(result, a)
-    addSon(result, newStrNodeP(nkTripleStrLit, p.tok.literal, p))
+    result.add(a)
+    result.add(newStrNodeP(nkTripleStrLit, p.tok.literal, p))
     getTok(p)
   else:
     result = a
@@ -596,7 +596,7 @@ proc parsePar(p: var TParser): PNode =
         # progress guaranteed
         while p.tok.tokType != tkParRi and p.tok.tokType != tkEof:
           var a = exprColonEqExpr(p)
-          addSon(result, a)
+          result.add(a)
           if p.tok.tokType != tkComma: break
           getTok(p)
           skipComment(p, a)
@@ -717,7 +717,7 @@ proc namedParams(p: var TParser, callee: PNode,
                  kind: TNodeKind, endTok: TTokType): PNode =
   let a = callee
   result = newNodeP(kind, p)
-  addSon(result, a)
+  result.add(a)
   # progress guaranteed
   exprColonEqExprListAux(p, endTok, result)
 
@@ -732,8 +732,8 @@ proc commandParam(p: var TParser, isFirstParam: var bool; mode: TPrimaryMode): P
     let lhs = result
     result = newNodeP(nkExprEqExpr, p)
     getTok(p)
-    addSon(result, lhs)
-    addSon(result, parseExpr(p))
+    result.add(lhs)
+    result.add(parseExpr(p))
   isFirstParam = false
 
 const
@@ -742,11 +742,11 @@ const
 
 proc commandExpr(p: var TParser; r: PNode; mode: TPrimaryMode): PNode =
   result = newNodeP(nkCommand, p)
-  addSon(result, r)
+  result.add(r)
   var isFirstParam = true
   # progress NOT guaranteed
   p.hasProgress = false
-  addSon result, commandParam(p, isFirstParam, mode)
+  result.add commandParam(p, isFirstParam, mode)
 
 proc primarySuffix(p: var TParser, r: PNode,
                    baseIndent: int, mode: TPrimaryMode): PNode =
@@ -769,13 +769,13 @@ proc primarySuffix(p: var TParser, r: PNode,
         # are parsed as a nkCommand with a single tuple argument (nkPar)
         if mode == pmTypeDef:
           result = newNodeP(nkCommand, p)
-          result.addSon r
-          result.addSon primary(p, pmNormal)
+          result.add r
+          result.add primary(p, pmNormal)
         else:
           result = commandExpr(p, result, mode)
         break
       result = namedParams(p, result, nkCall, tkParRi)
-      if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
+      if result.len > 1 and result[1].kind == nkExprColonExpr:
         result.kind = nkObjConstr
     of tkDot:
       # progress guaranteed
@@ -826,9 +826,9 @@ proc parseOperators(p: var TParser, headNode: PNode,
     optPar(p)
     # read sub-expression with higher priority:
     var b = simpleExprAux(p, opPrec + leftAssoc, modeB)
-    addSon(a, opNode)
-    addSon(a, result)
-    addSon(a, b)
+    a.add(opNode)
+    a.add(result)
+    a.add(b)
     result = a
     opPrec = getPrecedence(p.tok, false)
 
@@ -837,8 +837,8 @@ proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
   if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)) and
      mode == pmNormal:
     var pragmaExp = newNodeP(nkPragmaExpr, p)
-    pragmaExp.addSon result
-    pragmaExp.addSon p.parsePragma
+    pragmaExp.add result
+    pragmaExp.add p.parsePragma
     result = pragmaExp
   result = parseOperators(p, result, limit, mode)
 
@@ -861,18 +861,18 @@ proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
       getTok(p)                 # skip `if`, `when`, `elif`
       var branch = newNodeP(nkElifExpr, p)
       optInd(p, branch)
-      addSon(branch, parseExpr(p))
+      branch.add(parseExpr(p))
       colcom(p, branch)
-      addSon(branch, parseStmt(p))
+      branch.add(parseStmt(p))
       skipComment(p, branch)
-      addSon(result, branch)
+      result.add(branch)
       if p.tok.tokType != tkElif: break # or not sameOrNoInd(p): break
     if p.tok.tokType == tkElse: # and sameOrNoInd(p):
       var branch = newNodeP(nkElseExpr, p)
       eat(p, tkElse)
       colcom(p, branch)
-      addSon(branch, parseStmt(p))
-      addSon(result, branch)
+      branch.add(parseStmt(p))
+      result.add(branch)
   else:
     var
       b: PNode
@@ -881,13 +881,13 @@ proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
 
     getTok(p)
     let branch = newNodeP(nkElifExpr, p)
-    addSon(branch, parseExpr(p))
+    branch.add(parseExpr(p))
     colcom(p, branch)
     let oldInd = p.currInd
     if realInd(p):
       p.currInd = p.tok.indent
       wasIndented = true
-    addSon(branch, parseExpr(p))
+    branch.add(parseExpr(p))
     result.add branch
     while sameInd(p) or not wasIndented:
       case p.tok.tokType
@@ -895,14 +895,14 @@ proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
         b = newNodeP(nkElifExpr, p)
         getTok(p)
         optInd(p, b)
-        addSon(b, parseExpr(p))
+        b.add(parseExpr(p))
       of tkElse:
         b = newNodeP(nkElseExpr, p)
         getTok(p)
       else: break
       colcom(p, b)
-      addSon(b, parseStmt(p))
-      addSon(result, b)
+      b.add(parseStmt(p))
+      result.add(b)
       if b.kind == nkElseExpr: break
     if wasIndented:
       p.currInd = oldInd
@@ -920,7 +920,7 @@ proc parsePragma(p: var TParser): PNode =
     p.hasProgress = false
     var a = exprColonEqExpr(p)
     if not p.hasProgress: break
-    addSon(result, a)
+    result.add(a)
     if p.tok.tokType == tkComma:
       getTok(p)
       skipComment(p, a)
@@ -944,8 +944,8 @@ proc identVis(p: var TParser; allowDot=false): PNode =
     when defined(nimpretty):
       starWasExportMarker(p.em)
     result = newNodeP(nkPostfix, p)
-    addSon(result, newIdentNodeP(p.tok.ident, p))
-    addSon(result, a)
+    result.add(newIdentNodeP(p.tok.ident, p))
+    result.add(a)
     getTok(p)
   elif p.tok.tokType == tkDot and allowDot:
     result = dotExpr(p, a)
@@ -958,8 +958,8 @@ proc identWithPragma(p: var TParser; allowDot=false): PNode =
   var a = identVis(p, allowDot)
   if p.tok.tokType == tkCurlyDotLe:
     result = newNodeP(nkPragmaExpr, p)
-    addSon(result, a)
-    addSon(result, parsePragma(p))
+    result.add(a)
+    result.add(parsePragma(p))
   else:
     result = a
 
@@ -985,24 +985,24 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
       else: a = parseSymbol(p)
       if a.kind == nkEmpty: return
     else: break
-    addSon(result, a)
+    result.add(a)
     if p.tok.tokType != tkComma: break
     getTok(p)
     optInd(p, a)
   if p.tok.tokType == tkColon:
     getTok(p)
     optInd(p, result)
-    addSon(result, parseTypeDesc(p))
+    result.add(parseTypeDesc(p))
   else:
-    addSon(result, newNodeP(nkEmpty, p))
+    result.add(newNodeP(nkEmpty, p))
     if p.tok.tokType != tkEquals and withBothOptional notin flags:
       parMessage(p, "':' or '=' expected, but got '$1'", p.tok)
   if p.tok.tokType == tkEquals:
     getTok(p)
     optInd(p, result)
-    addSon(result, parseExpr(p))
+    result.add(parseExpr(p))
   else:
-    addSon(result, newNodeP(nkEmpty, p))
+    result.add(newNodeP(nkEmpty, p))
 
 proc parseTuple(p: var TParser, indentAllowed = false): PNode =
   #| inlTupleDecl = 'tuple'
@@ -1018,7 +1018,7 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
     # progress guaranteed
     while p.tok.tokType in {tkSymbol, tkAccent}:
       var a = parseIdentColonEquals(p, {})
-      addSon(result, a)
+      result.add(a)
       if p.tok.tokType notin {tkComma, tkSemiColon}: break
       when defined(nimpretty):
         commaWasSemicolon(p.em)
@@ -1038,7 +1038,7 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
             var a = parseIdentColonEquals(p, {})
             if p.tok.indent < 0 or p.tok.indent >= p.currInd:
               rawSkipComment(p, a)
-            addSon(result, a)
+            result.add(a)
           of tkEof: break
           else:
             parMessage(p, errIdentifierExpected, p.tok)
@@ -1055,7 +1055,7 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
   #| paramListColon = paramList? (':' optInd typeDesc)?
   var a: PNode
   result = newNodeP(nkFormalParams, p)
-  addSon(result, p.emptyNode) # return type
+  result.add(p.emptyNode) # return type
   when defined(nimpretty):
     inc p.em.doIndentMore
     inc p.em.keepIndents
@@ -1076,7 +1076,7 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
       else:
         parMessage(p, "expected closing ')'")
         break
-      addSon(result, a)
+      result.add(a)
       if p.tok.tokType notin {tkComma, tkSemiColon}: break
       when defined(nimpretty):
         commaWasSemicolon(p.em)
@@ -1089,7 +1089,7 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
   if hasRet and p.tok.indent < 0:
     getTok(p)
     optInd(p, result)
-    result.sons[0] = parseTypeDesc(p)
+    result[0] = parseTypeDesc(p)
   elif not retColon and not hasParLe:
     # Mark as "not there" in order to mark for deprecation in the semantic pass:
     result = p.emptyNode
@@ -1131,10 +1131,10 @@ proc parseProcExpr(p: var TParser; isExpr: bool; kind: TNodeKind): PNode =
   else:
     result = newNodeI(nkProcTy, info)
     if hasSignature:
-      addSon(result, params)
+      result.add(params)
       if kind == nkFuncDef:
         parMessage(p, "func keyword is not allowed in type descriptions, use proc with {.noSideEffect.} pragma instead")
-      addSon(result, pragmas)
+      result.add(pragmas)
 
 proc isExprStart(p: TParser): bool =
   case p.tok.tokType
@@ -1150,7 +1150,7 @@ proc parseSymbolList(p: var TParser, result: PNode) =
   while true:
     var s = parseSymbol(p, smAllowNil)
     if s.kind == nkEmpty: break
-    addSon(result, s)
+    result.add(s)
     if p.tok.tokType != tkComma: break
     getTok(p)
     optInd(p, s)
@@ -1163,7 +1163,7 @@ proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
   if p.tok.indent != -1 and p.tok.indent <= p.currInd: return
   optInd(p, result)
   if not isOperator(p.tok) and isExprStart(p):
-    addSon(result, primary(p, mode))
+    result.add(primary(p, mode))
   if kind == nkDistinctTy and p.tok.tokType == tkSymbol:
     # XXX document this feature!
     var nodeKind: TNodeKind
@@ -1175,7 +1175,7 @@ proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
       return result
     getTok(p)
     let list = newNodeP(nodeKind, p)
-    result.addSon list
+    result.add list
     parseSymbolList(p, list)
 
 proc parseVarTuple(p: var TParser): PNode
@@ -1186,22 +1186,22 @@ proc parseFor(p: var TParser): PNode =
   getTokNoInd(p)
   result = newNodeP(nkForStmt, p)
   if p.tok.tokType == tkParLe:
-    addSon(result, parseVarTuple(p))
+    result.add(parseVarTuple(p))
   else:
     var a = identWithPragma(p)
-    addSon(result, a)
+    result.add(a)
     while p.tok.tokType == tkComma:
       getTok(p)
       optInd(p, a)
       if p.tok.tokType == tkParLe:
-        addSon(result, parseVarTuple(p))
+        result.add(parseVarTuple(p))
         break
       a = identWithPragma(p)
-      addSon(result, a)
+      result.add(a)
   eat(p, tkIn)
-  addSon(result, parseExpr(p))
+  result.add(parseExpr(p))
   colcom(p, result)
-  addSon(result, parseStmt(p))
+  result.add(parseStmt(p))
 
 template nimprettyDontTouch(body) =
   when defined(nimpretty):
@@ -1255,16 +1255,16 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
     let isSigil = isSigilLike(p.tok)
     result = newNodeP(nkPrefix, p)
     var a = newIdentNodeP(p.tok.ident, p)
-    addSon(result, a)
+    result.add(a)
     getTok(p)
     optInd(p, a)
     if isSigil:
       #XXX prefix operators
       let baseInd = p.lex.currLineIndent
-      addSon(result, primary(p, pmSkipSuffix))
+      result.add(primary(p, pmSkipSuffix))
       result = primarySuffix(p, result, baseInd, mode)
     else:
-      addSon(result, primary(p, pmNormal))
+      result.add(primary(p, pmNormal))
     return
 
   case p.tok.tokType:
@@ -1298,7 +1298,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
     result = newNodeP(nkBind, p)
     getTok(p)
     optInd(p, result)
-    addSon(result, primary(p, pmNormal))
+    result.add(primary(p, pmNormal))
   of tkVar: result = parseTypeDescKAux(p, nkVarTy, mode)
   of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode)
   of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode)
@@ -1397,7 +1397,7 @@ proc postExprBlocks(p: var TParser, x: PNode): PNode =
           nextBlock = newNodeP(nkElifBranch, p)
           getTok(p)
           optInd(p, nextBlock)
-          nextBlock.addSon parseExpr(p)
+          nextBlock.add parseExpr(p)
         of tkExcept:
           nextBlock = newNodeP(nkExceptBranch, p)
           exprList(p, tkColon, nextBlock)
@@ -1406,7 +1406,7 @@ proc postExprBlocks(p: var TParser, x: PNode): PNode =
           getTok(p)
         else: break
         eat(p, tkColon)
-        nextBlock.addSon parseStmt(p)
+        nextBlock.add parseStmt(p)
 
       nextBlock.flags.incl nfBlockArg
       result.add nextBlock
@@ -1430,8 +1430,8 @@ proc parseExprStmt(p: var TParser): PNode =
     optInd(p, result)
     var b = parseExpr(p)
     b = postExprBlocks(p, b)
-    addSon(result, a)
-    addSon(result, b)
+    result.add(a)
+    result.add(b)
   else:
     # simpleExpr parsed 'p a' from 'p a, b'?
     var isFirstParam = false
@@ -1440,12 +1440,12 @@ proc parseExprStmt(p: var TParser): PNode =
       while true:
         getTok(p)
         optInd(p, result)
-        addSon(result, commandParam(p, isFirstParam, pmNormal))
+        result.add(commandParam(p, isFirstParam, pmNormal))
         if p.tok.tokType != tkComma: break
     elif p.tok.indent < 0 and isExprStart(p):
       result = newNode(nkCommand, a.info, @[a])
       while true:
-        addSon(result, commandParam(p, isFirstParam, pmNormal))
+        result.add(commandParam(p, isFirstParam, pmNormal))
         if p.tok.tokType != tkComma: break
         getTok(p)
         optInd(p, result)
@@ -1472,7 +1472,7 @@ proc parseImport(p: var TParser, kind: TNodeKind): PNode =
   getTok(p)                   # skip `import` or `export`
   optInd(p, result)
   var a = parseModuleName(p, kind)
-  addSon(result, a)
+  result.add(a)
   if p.tok.tokType in {tkComma, tkExcept}:
     if p.tok.tokType == tkExcept:
       result.kind = succ(kind)
@@ -1483,7 +1483,7 @@ proc parseImport(p: var TParser, kind: TNodeKind): PNode =
       p.hasProgress = false
       a = parseModuleName(p, kind)
       if a.kind == nkEmpty or not p.hasProgress: break
-      addSon(result, a)
+      result.add(a)
       if p.tok.tokType != tkComma: break
       getTok(p)
       optInd(p, a)
@@ -1499,7 +1499,7 @@ proc parseIncludeStmt(p: var TParser): PNode =
     p.hasProgress = false
     var a = parseExpr(p)
     if a.kind == nkEmpty or not p.hasProgress: break
-    addSon(result, a)
+    result.add(a)
     if p.tok.tokType != tkComma: break
     getTok(p)
     optInd(p, a)
@@ -1511,7 +1511,7 @@ proc parseFromStmt(p: var TParser): PNode =
   getTok(p)                   # skip `from`
   optInd(p, result)
   var a = parseModuleName(p, nkImportStmt)
-  addSon(result, a)           #optInd(p, a);
+  result.add(a)           #optInd(p, a);
   eat(p, tkImport)
   optInd(p, result)
   while true:
@@ -1519,7 +1519,7 @@ proc parseFromStmt(p: var TParser): PNode =
     p.hasProgress = false
     a = parseExpr(p)
     if a.kind == nkEmpty or not p.hasProgress: break
-    addSon(result, a)
+    result.add(a)
     if p.tok.tokType != tkComma: break
     getTok(p)
     optInd(p, a)
@@ -1536,15 +1536,15 @@ proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
   getTok(p)
   if p.tok.tokType == tkComment:
     skipComment(p, result)
-    addSon(result, p.emptyNode)
+    result.add(p.emptyNode)
   elif p.tok.indent >= 0 and p.tok.indent <= p.currInd or not isExprStart(p):
     # NL terminates:
-    addSon(result, p.emptyNode)
+    result.add(p.emptyNode)
     # nimpretty here!
   else:
     var e = parseExpr(p)
     e = postExprBlocks(p, e)
-    addSon(result, e)
+    result.add(e)
 
 proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
   #| condStmt = expr colcom stmt COMMENT?
@@ -1557,27 +1557,27 @@ proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
     getTok(p)                 # skip `if`, `when`, `elif`
     var branch = newNodeP(nkElifBranch, p)
     optInd(p, branch)
-    addSon(branch, parseExpr(p))
+    branch.add(parseExpr(p))
     colcom(p, branch)
-    addSon(branch, parseStmt(p))
+    branch.add(parseStmt(p))
     skipComment(p, branch)
-    addSon(result, branch)
+    result.add(branch)
     if p.tok.tokType != tkElif or not sameOrNoInd(p): break
   if p.tok.tokType == tkElse and sameOrNoInd(p):
     var branch = newNodeP(nkElse, p)
     eat(p, tkElse)
     colcom(p, branch)
-    addSon(branch, parseStmt(p))
-    addSon(result, branch)
+    branch.add(parseStmt(p))
+    result.add(branch)
 
 proc parseWhile(p: var TParser): PNode =
   #| whileStmt = 'while' expr colcom stmt
   result = newNodeP(nkWhileStmt, p)
   getTok(p)
   optInd(p, result)
-  addSon(result, parseExpr(p))
+  result.add(parseExpr(p))
   colcom(p, result)
-  addSon(result, parseStmt(p))
+  result.add(parseStmt(p))
 
 proc parseCase(p: var TParser): PNode =
   #| ofBranch = 'of' exprList colcom stmt
@@ -1593,7 +1593,7 @@ proc parseCase(p: var TParser): PNode =
     wasIndented = false
   result = newNodeP(nkCaseStmt, p)
   getTok(p)
-  addSon(result, parseExpr(p))
+  result.add(parseExpr(p))
   if p.tok.tokType == tkColon: getTok(p)
   skipComment(p, result)
 
@@ -1613,14 +1613,14 @@ proc parseCase(p: var TParser): PNode =
       b = newNodeP(nkElifBranch, p)
       getTok(p)
       optInd(p, b)
-      addSon(b, parseExpr(p))
+      b.add(parseExpr(p))
     of tkElse:
       b = newNodeP(nkElse, p)
       getTok(p)
     else: break
     colcom(p, b)
-    addSon(b, parseStmt(p))
-    addSon(result, b)
+    b.add(parseStmt(p))
+    result.add(b)
     if b.kind == nkElse: break
 
   if wasIndented:
@@ -1636,7 +1636,7 @@ proc parseTry(p: var TParser; isExpr: bool): PNode =
   result = newNodeP(nkTryStmt, p)
   getTok(p)
   colcom(p, result)
-  addSon(result, parseStmt(p))
+  result.add(parseStmt(p))
   var b: PNode = nil
   while sameOrNoInd(p) or isExpr:
     case p.tok.tokType
@@ -1648,8 +1648,8 @@ proc parseTry(p: var TParser; isExpr: bool): PNode =
       getTok(p)
     else: break
     colcom(p, b)
-    addSon(b, parseStmt(p))
-    addSon(result, b)
+    b.add(parseStmt(p))
+    result.add(b)
   if b == nil: parMessage(p, "expected 'except'")
 
 proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode =
@@ -1657,17 +1657,17 @@ proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode =
   result = newNodeP(kind, p)
   getTok(p)
   colcom(p, result)
-  addSon(result, parseStmt(p))
+  result.add(parseStmt(p))
 
 proc parseBlock(p: var TParser): PNode =
   #| blockStmt = 'block' symbol? colcom stmt
   #| blockExpr = 'block' symbol? colcom stmt
   result = newNodeP(nkBlockStmt, p)
   getTokNoInd(p)
-  if p.tok.tokType == tkColon: addSon(result, p.emptyNode)
-  else: addSon(result, parseSymbol(p))
+  if p.tok.tokType == tkColon: result.add(p.emptyNode)
+  else: result.add(parseSymbol(p))
   colcom(p, result)
-  addSon(result, parseStmt(p))
+  result.add(parseStmt(p))
 
 proc parseStaticOrDefer(p: var TParser; k: TNodeKind): PNode =
   #| staticStmt = 'static' colcom stmt
@@ -1675,22 +1675,21 @@ proc parseStaticOrDefer(p: var TParser; k: TNodeKind): PNode =
   result = newNodeP(k, p)
   getTok(p)
   colcom(p, result)
-  addSon(result, parseStmt(p))
+  result.add(parseStmt(p))
 
 proc parseAsm(p: var TParser): PNode =
   #| asmStmt = 'asm' pragma? (STR_LIT | RSTR_LIT | TRIPLESTR_LIT)
   result = newNodeP(nkAsmStmt, p)
   getTokNoInd(p)
-  if p.tok.tokType == tkCurlyDotLe: addSon(result, parsePragma(p))
-  else: addSon(result, p.emptyNode)
+  if p.tok.tokType == tkCurlyDotLe: result.add(parsePragma(p))
+  else: result.add(p.emptyNode)
   case p.tok.tokType
-  of tkStrLit: addSon(result, newStrNodeP(nkStrLit, p.tok.literal, p))
-  of tkRStrLit: addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p))
-  of tkTripleStrLit: addSon(result,
-                            newStrNodeP(nkTripleStrLit, p.tok.literal, p))
+  of tkStrLit: result.add(newStrNodeP(nkStrLit, p.tok.literal, p))
+  of tkRStrLit: result.add(newStrNodeP(nkRStrLit, p.tok.literal, p))
+  of tkTripleStrLit: result.add(newStrNodeP(nkTripleStrLit, p.tok.literal, p))
   else:
     parMessage(p, "the 'asm' statement takes a string literal")
-    addSon(result, p.emptyNode)
+    result.add(p.emptyNode)
     return
   getTok(p)
 
@@ -1704,30 +1703,30 @@ proc parseGenericParam(p: var TParser): PNode =
     of tkIn, tkOut:
       let x = p.lex.cache.getIdent(if p.tok.tokType == tkIn: "in" else: "out")
       a = newNodeP(nkPrefix, p)
-      a.addSon newIdentNodeP(x, p)
+      a.add newIdentNodeP(x, p)
       getTok(p)
       expectIdent(p)
-      a.addSon(parseSymbol(p))
+      a.add(parseSymbol(p))
     of tkSymbol, tkAccent:
       a = parseSymbol(p)
       if a.kind == nkEmpty: return
     else: break
-    addSon(result, a)
+    result.add(a)
     if p.tok.tokType != tkComma: break
     getTok(p)
     optInd(p, a)
   if p.tok.tokType == tkColon:
     getTok(p)
     optInd(p, result)
-    addSon(result, parseExpr(p))
+    result.add(parseExpr(p))
   else:
-    addSon(result, p.emptyNode)
+    result.add(p.emptyNode)
   if p.tok.tokType == tkEquals:
     getTok(p)
     optInd(p, result)
-    addSon(result, parseExpr(p))
+    result.add(parseExpr(p))
   else:
-    addSon(result, p.emptyNode)
+    result.add(p.emptyNode)
 
 proc parseGenericParamList(p: var TParser): PNode =
   #| genericParamList = '[' optInd
@@ -1738,7 +1737,7 @@ proc parseGenericParamList(p: var TParser): PNode =
   # progress guaranteed
   while p.tok.tokType in {tkSymbol, tkAccent, tkIn, tkOut}:
     var a = parseGenericParam(p)
-    addSon(result, a)
+    result.add(a)
     if p.tok.tokType notin {tkComma, tkSemiColon}: break
     when defined(nimpretty):
       commaWasSemicolon(p.em)
@@ -1760,24 +1759,24 @@ proc parseRoutine(p: var TParser, kind: TNodeKind): PNode =
   result = newNodeP(kind, p)
   getTok(p)
   optInd(p, result)
-  addSon(result, identVis(p))
-  if p.tok.tokType == tkCurlyLe and p.validInd: addSon(result, p.parsePattern)
-  else: addSon(result, p.emptyNode)
+  result.add(identVis(p))
+  if p.tok.tokType == tkCurlyLe and p.validInd: result.add(p.parsePattern)
+  else: result.add(p.emptyNode)
   if p.tok.tokType == tkBracketLe and p.validInd:
     result.add(p.parseGenericParamList)
   else:
-    addSon(result, p.emptyNode)
-  addSon(result, p.parseParamList)
-  if p.tok.tokType == tkCurlyDotLe and p.validInd: addSon(result, p.parsePragma)
-  else: addSon(result, p.emptyNode)
+    result.add(p.emptyNode)
+  result.add(p.parseParamList)
+  if p.tok.tokType == tkCurlyDotLe and p.validInd: result.add(p.parsePragma)
+  else: result.add(p.emptyNode)
   # empty exception tracking:
-  addSon(result, p.emptyNode)
+  result.add(p.emptyNode)
   if p.tok.tokType == tkEquals and p.validInd:
     getTok(p)
     skipComment(p, result)
-    addSon(result, parseStmt(p))
+    result.add(parseStmt(p))
   else:
-    addSon(result, p.emptyNode)
+    result.add(p.emptyNode)
   indAndComment(p, result)
 
 proc newCommentStmt(p: var TParser): PNode =
@@ -1804,17 +1803,17 @@ proc parseSection(p: var TParser, kind: TNodeKind,
         of tkSymbol, tkAccent, tkParLe:
           var a = defparser(p)
           skipComment(p, a)
-          addSon(result, a)
+          result.add(a)
         of tkComment:
           var a = newCommentStmt(p)
-          addSon(result, a)
+          result.add(a)
         else:
           parMessage(p, errIdentifierExpected, p.tok)
           break
     if result.len == 0: parMessage(p, errIdentifierExpected, p.tok)
   elif p.tok.tokType in {tkSymbol, tkAccent, tkParLe} and p.tok.indent < 0:
     # tkParLe is allowed for ``var (x, y) = ...`` tuple parsing
-    addSon(result, defparser(p))
+    result.add(defparser(p))
   else:
     parMessage(p, errIdentifierExpected, p.tok)
 
@@ -1822,7 +1821,7 @@ proc parseEnum(p: var TParser): PNode =
   #| enum = 'enum' optInd (symbol optPragmas optInd ('=' optInd expr COMMENT?)? comma?)+
   result = newNodeP(nkEnumTy, p)
   getTok(p)
-  addSon(result, p.emptyNode)
+  result.add(p.emptyNode)
   optInd(p, result)
   flexComment(p, result)
   # progress guaranteed
@@ -1835,11 +1834,11 @@ proc parseEnum(p: var TParser): PNode =
     if p.tok.tokType == tkCurlyDotLe:
       pragma = optPragmas(p)
       symPragma = newNodeP(nkPragmaExpr, p)
-      addSon(symPragma, a)
-      addSon(symPragma, pragma)
+      symPragma.add(a)
+      symPragma.add(pragma)
     # nimpretty support here
     if p.tok.indent >= 0 and p.tok.indent <= p.currInd:
-      add(result, symPragma)
+      result.add(symPragma)
       break
 
     if p.tok.tokType == tkEquals and p.tok.indent < 0:
@@ -1847,8 +1846,8 @@ proc parseEnum(p: var TParser): PNode =
       optInd(p, symPragma)
       var b = symPragma
       symPragma = newNodeP(nkEnumFieldDef, p)
-      addSon(symPragma, b)
-      addSon(symPragma, parseExpr(p))
+      symPragma.add(b)
+      symPragma.add(parseExpr(p))
       if p.tok.indent < 0 or p.tok.indent >= p.currInd:
         rawSkipComment(p, symPragma)
     if p.tok.tokType == tkComma and p.tok.indent < 0:
@@ -1857,7 +1856,7 @@ proc parseEnum(p: var TParser): PNode =
     else:
       if p.tok.indent < 0 or p.tok.indent >= p.currInd:
         rawSkipComment(p, symPragma)
-    addSon(result, symPragma)
+    result.add(symPragma)
     if p.tok.indent >= 0 and p.tok.indent <= p.currInd or
         p.tok.tokType == tkEof:
       break
@@ -1875,19 +1874,19 @@ proc parseObjectWhen(p: var TParser): PNode =
     getTok(p)                 # skip `when`, `elif`
     var branch = newNodeP(nkElifBranch, p)
     optInd(p, branch)
-    addSon(branch, parseExpr(p))
+    branch.add(parseExpr(p))
     colcom(p, branch)
-    addSon(branch, parseObjectPart(p))
+    branch.add(parseObjectPart(p))
     flexComment(p, branch)
-    addSon(result, branch)
+    result.add(branch)
     if p.tok.tokType != tkElif: break
   if p.tok.tokType == tkElse and sameInd(p):
     var branch = newNodeP(nkElse, p)
     eat(p, tkElse)
     colcom(p, branch)
-    addSon(branch, parseObjectPart(p))
+    branch.add(parseObjectPart(p))
     flexComment(p, branch)
-    addSon(result, branch)
+    result.add(branch)
 
 proc parseObjectCase(p: var TParser): PNode =
   #| objectBranch = 'of' exprList colcom objectPart
@@ -1900,11 +1899,11 @@ proc parseObjectCase(p: var TParser): PNode =
   result = newNodeP(nkRecCase, p)
   getTokNoInd(p)
   var a = newNodeP(nkIdentDefs, p)
-  addSon(a, identWithPragma(p))
+  a.add(identWithPragma(p))
   eat(p, tkColon)
-  addSon(a, parseTypeDesc(p))
-  addSon(a, p.emptyNode)
-  addSon(result, a)
+  a.add(parseTypeDesc(p))
+  a.add(p.emptyNode)
+  result.add(a)
   if p.tok.tokType == tkColon: getTok(p)
   flexComment(p, result)
   var wasIndented = false
@@ -1928,8 +1927,8 @@ proc parseObjectCase(p: var TParser): PNode =
     if fields.kind == nkEmpty:
       parMessage(p, errIdentifierExpected, p.tok)
       fields = newNodeP(nkNilLit, p) # don't break further semantic checking
-    addSon(b, fields)
-    addSon(result, b)
+    b.add(fields)
+    result.add(b)
     if b.kind == nkElse: break
   if wasIndented:
     p.currInd = oldInd
@@ -1944,7 +1943,7 @@ proc parseObjectPart(p: var TParser): PNode =
       while sameInd(p):
         case p.tok.tokType
         of tkCase, tkWhen, tkSymbol, tkAccent, tkNil, tkDiscard:
-          addSon(result, parseObjectPart(p))
+          result.add(parseObjectPart(p))
         else:
           parMessage(p, errIdentifierExpected, p.tok)
           break
@@ -1971,23 +1970,23 @@ proc parseObject(p: var TParser): PNode =
   if p.tok.tokType == tkCurlyDotLe and p.validInd:
     # Deprecated since v0.20.0
     parMessage(p, warnDeprecated, "type pragmas follow the type name; this form of writing pragmas is deprecated")
-    addSon(result, parsePragma(p))
+    result.add(parsePragma(p))
   else:
-    addSon(result, p.emptyNode)
+    result.add(p.emptyNode)
   if p.tok.tokType == tkOf and p.tok.indent < 0:
     var a = newNodeP(nkOfInherit, p)
     getTok(p)
-    addSon(a, parseTypeDesc(p))
-    addSon(result, a)
+    a.add(parseTypeDesc(p))
+    result.add(a)
   else:
-    addSon(result, p.emptyNode)
+    result.add(p.emptyNode)
   if p.tok.tokType == tkComment:
     skipComment(p, result)
   # an initial IND{>} HAS to follow:
   if not realInd(p):
-    addSon(result, p.emptyNode)
+    result.add(p.emptyNode)
     return
-  addSon(result, parseObjectPart(p))
+  result.add(parseObjectPart(p))
 
 proc parseTypeClassParam(p: var TParser): PNode =
   let modifier = case p.tok.tokType
@@ -2001,7 +2000,7 @@ proc parseTypeClassParam(p: var TParser): PNode =
   if modifier != nkEmpty:
     result = newNodeP(modifier, p)
     getTok(p)
-    result.addSon(p.parseSymbol)
+    result.add(p.parseSymbol)
   else:
     result = p.parseSymbol
 
@@ -2012,33 +2011,33 @@ proc parseTypeClass(p: var TParser): PNode =
   result = newNodeP(nkTypeClassTy, p)
   getTok(p)
   var args = newNodeP(nkArgList, p)
-  addSon(result, args)
-  addSon(args, p.parseTypeClassParam)
+  result.add(args)
+  args.add(p.parseTypeClassParam)
   while p.tok.tokType == tkComma:
     getTok(p)
-    addSon(args, p.parseTypeClassParam)
+    args.add(p.parseTypeClassParam)
   if p.tok.tokType == tkCurlyDotLe and p.validInd:
-    addSon(result, parsePragma(p))
+    result.add(parsePragma(p))
   else:
-    addSon(result, p.emptyNode)
+    result.add(p.emptyNode)
   if p.tok.tokType == tkOf and p.tok.indent < 0:
     var a = newNodeP(nkOfInherit, p)
     getTok(p)
     # progress guaranteed
     while true:
-      addSon(a, parseTypeDesc(p))
+      a.add(parseTypeDesc(p))
       if p.tok.tokType != tkComma: break
       getTok(p)
-    addSon(result, a)
+    result.add(a)
   else:
-    addSon(result, p.emptyNode)
+    result.add(p.emptyNode)
   if p.tok.tokType == tkComment:
     skipComment(p, result)
   # an initial IND{>} HAS to follow:
   if not realInd(p):
-    addSon(result, p.emptyNode)
+    result.add(p.emptyNode)
   else:
-    addSon(result, parseStmt(p))
+    result.add(parseStmt(p))
 
 proc parseTypeDef(p: var TParser): PNode =
   #|
@@ -2055,8 +2054,8 @@ proc parseTypeDef(p: var TParser): PNode =
   if p.tok.tokType == tkCurlyDotLe:
     pragma = optPragmas(p)
     identPragma = newNodeP(nkPragmaExpr, p)
-    addSon(identPragma, identifier)
-    addSon(identPragma, pragma)
+    identPragma.add(identifier)
+    identPragma.add(pragma)
     noPragmaYet = false
 
   if p.tok.tokType == tkBracketLe and p.validInd:
@@ -2071,21 +2070,21 @@ proc parseTypeDef(p: var TParser): PNode =
     pragma = optPragmas(p)
     if pragma.kind != nkEmpty:
       identPragma = newNodeP(nkPragmaExpr, p)
-      addSon(identPragma, identifier)
-      addSon(identPragma, pragma)
+      identPragma.add(identifier)
+      identPragma.add(pragma)
   elif p.tok.tokType == tkCurlyDotLe:
     parMessage(p, errGenerated, "pragma already present")
 
-  addSon(result, identPragma)
-  addSon(result, genericParam)
+  result.add(identPragma)
+  result.add(genericParam)
 
   if p.tok.tokType == tkEquals:
     result.info = parLineInfo(p)
     getTok(p)
     optInd(p, result)
-    addSon(result, parseTypeDefAux(p))
+    result.add(parseTypeDefAux(p))
   else:
-    addSon(result, p.emptyNode)
+    result.add(p.emptyNode)
   indAndComment(p, result)    # special extension!
 
 proc parseVarTuple(p: var TParser): PNode =
@@ -2096,11 +2095,11 @@ proc parseVarTuple(p: var TParser): PNode =
   # progress guaranteed
   while p.tok.tokType in {tkSymbol, tkAccent}:
     var a = identWithPragma(p, allowDot=true)
-    addSon(result, a)
+    result.add(a)
     if p.tok.tokType != tkComma: break
     getTok(p)
     skipComment(p, a)
-  addSon(result, p.emptyNode)         # no type desc
+  result.add(p.emptyNode)         # no type desc
   optPar(p)
   eat(p, tkParRi)
 
@@ -2111,7 +2110,7 @@ proc parseVariable(p: var TParser): PNode =
     result = parseVarTuple(p)
     eat(p, tkEquals)
     optInd(p, result)
-    addSon(result, parseExpr(p))
+    result.add(parseExpr(p))
   else: result = parseIdentColonEquals(p, {withPragma, withDot})
   result[^1] = postExprBlocks(p, result[^1])
   indAndComment(p, result)
@@ -2121,17 +2120,17 @@ proc parseConstant(p: var TParser): PNode =
   if p.tok.tokType == tkParLe: result = parseVarTuple(p)
   else:
     result = newNodeP(nkConstDef, p)
-    addSon(result, identWithPragma(p))
+    result.add(identWithPragma(p))
     if p.tok.tokType == tkColon:
       getTok(p)
       optInd(p, result)
-      addSon(result, parseTypeDesc(p))
+      result.add(parseTypeDesc(p))
     else:
-      addSon(result, p.emptyNode)
+      result.add(p.emptyNode)
   eat(p, tkEquals)
   optInd(p, result)
-  #addSon(result, parseStmtListExpr(p))
-  addSon(result, parseExpr(p))
+  #add(result, parseStmtListExpr(p))
+  result.add(parseExpr(p))
   result[^1] = postExprBlocks(p, result[^1])
   indAndComment(p, result)
 
@@ -2144,7 +2143,7 @@ proc parseBind(p: var TParser, k: TNodeKind): PNode =
   # progress guaranteed
   while true:
     var a = qualifiedIdent(p)
-    addSon(result, a)
+    result.add(a)
     if p.tok.tokType != tkComma: break
     getTok(p)
     optInd(p, a)
@@ -2223,7 +2222,7 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
     if p.tok.tokType == tkParLe:
       getTok(p)
       result = newNodeP(nkTypeOfExpr, p)
-      result.addSon(primary(p, pmTypeDesc))
+      result.add(primary(p, pmTypeDesc))
       eat(p, tkParRi)
       result = parseOperators(p, result, -1, pmNormal)
     else:
@@ -2268,7 +2267,7 @@ proc parseStmt(p: var TParser): PNode =
         p.hasProgress = false
         var a = complexOrSimpleStmt(p)
         if a.kind != nkEmpty:
-          addSon(result, a)
+          result.add(a)
         else:
           # This is done to make the new 'if' expressions work better.
           # XXX Eventually we need to be more strict here.
@@ -2310,7 +2309,7 @@ proc parseAll(p: var TParser): PNode =
     p.hasProgress = false
     var a = complexOrSimpleStmt(p)
     if a.kind != nkEmpty and p.hasProgress:
-      addSon(result, a)
+      result.add(a)
     else:
       parMessage(p, errExprExpected, p.tok)
       # bugfix: consume a token here to prevent an endless loop:
diff --git a/compiler/passes.nim b/compiler/passes.nim
index d6bbd4d14..9f562d615 100644
--- a/compiler/passes.nim
+++ b/compiler/passes.nim
@@ -67,21 +67,21 @@ proc carryPasses*(g: ModuleGraph; nodes: PNode, module: PSym;
 
 proc openPasses(g: ModuleGraph; a: var TPassContextArray;
                 module: PSym) =
-  for i in 0 ..< g.passes.len:
+  for i in 0..<g.passes.len:
     if not isNil(g.passes[i].open):
       a[i] = g.passes[i].open(g, module)
     else: a[i] = nil
 
 proc closePasses(graph: ModuleGraph; a: var TPassContextArray) =
   var m: PNode = nil
-  for i in 0 ..< graph.passes.len:
+  for i in 0..<graph.passes.len:
     if not isNil(graph.passes[i].close): m = graph.passes[i].close(graph, a[i], m)
     a[i] = nil                # free the memory here
 
 proc processTopLevelStmt(graph: ModuleGraph, n: PNode, a: var TPassContextArray): bool =
   # this implements the code transformation pipeline
   var m = n
-  for i in 0 ..< graph.passes.len:
+  for i in 0..<graph.passes.len:
     if not isNil(graph.passes[i].process):
       m = graph.passes[i].process(a[i], m)
       if isNil(m): return false
@@ -104,7 +104,7 @@ proc processImplicits(graph: ModuleGraph; implicits: seq[string], nodeKind: TNod
       var importStmt = newNodeI(nodeKind, m.info)
       var str = newStrNode(nkStrLit, module)
       str.info = m.info
-      importStmt.addSon str
+      importStmt.add str
       if not processTopLevelStmt(graph, importStmt, a): break
 
 const
@@ -135,7 +135,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool {
   prepareConfigNotes(graph, module)
   if module.id < 0:
     # new module caching mechanism:
-    for i in 0 ..< graph.passes.len:
+    for i in 0..<graph.passes.len:
       if not isNil(graph.passes[i].open) and not graph.passes[i].isFrontend:
         a[i] = graph.passes[i].open(graph, module)
       else:
@@ -144,14 +144,14 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool {
     if not graph.stopCompile():
       let n = loadNode(graph, module)
       var m = n
-      for i in 0 ..< graph.passes.len:
+      for i in 0..<graph.passes.len:
         if not isNil(graph.passes[i].process) and not graph.passes[i].isFrontend:
           m = graph.passes[i].process(a[i], m)
           if isNil(m):
             break
 
     var m: PNode = nil
-    for i in 0 ..< graph.passes.len:
+    for i in 0..<graph.passes.len:
       if not isNil(graph.passes[i].close) and not graph.passes[i].isFrontend:
         m = graph.passes[i].close(graph, a[i], m)
       a[i] = nil
diff --git a/compiler/patterns.nim b/compiler/patterns.nim
index 7e66ae591..f24d25c5c 100644
--- a/compiler/patterns.nim
+++ b/compiler/patterns.nim
@@ -58,18 +58,18 @@ proc sameTrees*(a, b: PNode): bool =
     of nkEmpty, nkNilLit: result = true
     of nkType: result = sameTypeOrNil(a.typ, b.typ)
     else:
-      if len(a) == len(b):
-        for i in 0 ..< len(a):
-          if not sameTrees(a.sons[i], b.sons[i]): return
+      if a.len == b.len:
+        for i in 0..<a.len:
+          if not sameTrees(a[i], b[i]): return
         result = true
 
 proc inSymChoice(sc, x: PNode): bool =
   if sc.kind == nkClosedSymChoice:
     for i in 0..<sc.len:
-      if sc.sons[i].sym == x.sym: return true
+      if sc[i].sym == x.sym: return true
   elif sc.kind == nkOpenSymChoice:
     # same name suffices for open sym choices!
-    result = sc.sons[0].sym.name.id == x.sym.name.id
+    result = sc[0].sym.name.id == x.sym.name.id
 
 proc checkTypes(c: PPatternContext, p: PSym, n: PNode): bool =
   # check param constraints first here as this is quite optimized:
@@ -85,8 +85,8 @@ proc isPatternParam(c: PPatternContext, p: PNode): bool {.inline.} =
   result = p.kind == nkSym and p.sym.kind == skParam and p.sym.owner == c.owner
 
 proc matchChoice(c: PPatternContext, p, n: PNode): bool =
-  for i in 1 ..< p.len:
-    if matches(c, p.sons[i], n): return true
+  for i in 1..<p.len:
+    if matches(c, p[i], n): return true
 
 proc bindOrCheck(c: PPatternContext, param: PSym, n: PNode): bool =
   var pp = getLazy(c, param)
@@ -103,7 +103,7 @@ proc gather(c: PPatternContext, param: PSym, n: PNode) =
     pp.add(n)
   else:
     pp = newNodeI(nkArgList, n.info, 1)
-    pp.sons[0] = n
+    pp[0] = n
     putLazy(c, param, pp)
 
 proc matchNested(c: PPatternContext, p, n: PNode, rpn: bool): bool =
@@ -111,24 +111,24 @@ proc matchNested(c: PPatternContext, p, n: PNode, rpn: bool): bool =
   proc matchStarAux(c: PPatternContext, op, n, arglist: PNode,
                     rpn: bool): bool =
     result = true
-    if n.kind in nkCallKinds and matches(c, op.sons[1], n.sons[0]):
-      for i in 1..len(n)-1:
+    if n.kind in nkCallKinds and matches(c, op[1], n[0]):
+      for i in 1..<n.len:
         if not matchStarAux(c, op, n[i], arglist, rpn): return false
-      if rpn: arglist.add(n.sons[0])
-    elif n.kind == nkHiddenStdConv and n.sons[1].kind == nkBracket:
-      let n = n.sons[1]
+      if rpn: arglist.add(n[0])
+    elif n.kind == nkHiddenStdConv and n[1].kind == nkBracket:
+      let n = n[1]
       for i in 0..<n.len:
         if not matchStarAux(c, op, n[i], arglist, rpn): return false
-    elif checkTypes(c, p.sons[2].sym, n):
-      add(arglist, n)
+    elif checkTypes(c, p[2].sym, n):
+      arglist.add(n)
     else:
       result = false
 
   if n.kind notin nkCallKinds: return false
-  if matches(c, p.sons[1], n.sons[0]):
+  if matches(c, p[1], n[0]):
     var arglist = newNodeI(nkArgList, n.info)
     if matchStarAux(c, p, n, arglist, rpn):
-      result = bindOrCheck(c, p.sons[2].sym, arglist)
+      result = bindOrCheck(c, p[2].sym, arglist)
 
 proc matches(c: PPatternContext, p, n: PNode): bool =
   let n = skipHidden(n)
@@ -146,24 +146,24 @@ proc matches(c: PPatternContext, p, n: PNode): bool =
     elif matches(c, p, n.sym.ast): result = true
   elif p.kind == nkPattern:
     # pattern operators: | *
-    let opr = p.sons[0].ident.s
+    let opr = p[0].ident.s
     case opr
     of "|": result = matchChoice(c, p, n)
     of "*": result = matchNested(c, p, n, rpn=false)
     of "**": result = matchNested(c, p, n, rpn=true)
-    of "~": result = not matches(c, p.sons[1], n)
+    of "~": result = not matches(c, p[1], n)
     else: doAssert(false, "invalid pattern")
     # template {add(a, `&` * b)}(a: string{noalias}, b: varargs[string]) =
-    #   add(a, b)
+    #   a.add(b)
   elif p.kind == nkCurlyExpr:
-    if p.sons[1].kind == nkPrefix:
-      if matches(c, p.sons[0], n):
-        gather(c, p.sons[1].sons[1].sym, n)
+    if p[1].kind == nkPrefix:
+      if matches(c, p[0], n):
+        gather(c, p[1][1].sym, n)
         result = true
     else:
-      assert isPatternParam(c, p.sons[1])
-      if matches(c, p.sons[0], n):
-        result = bindOrCheck(c, p.sons[1].sym, n)
+      assert isPatternParam(c, p[1])
+      if matches(c, p[0], n):
+        result = bindOrCheck(c, p[1].sym, n)
   elif sameKinds(p, n):
     case p.kind
     of nkSym: result = p.sym == n.sym
@@ -174,42 +174,41 @@ proc matches(c: PPatternContext, p, n: PNode): bool =
     of nkEmpty, nkNilLit, nkType:
       result = true
     else:
-      var plen = len(p)
       # special rule for p(X) ~ f(...); this also works for stuff like
       # partial case statements, etc! - Not really ... :-/
       let v = lastSon(p)
       if isPatternParam(c, v) and v.sym.typ.kind == tyVarargs:
         var arglist: PNode
-        if plen <= len(n):
-          for i in 0 .. plen - 2:
-            if not matches(c, p.sons[i], n.sons[i]): return
-          if plen == len(n) and lastSon(n).kind == nkHiddenStdConv and
-              lastSon(n).sons[1].kind == nkBracket:
+        if p.len <= n.len:
+          for i in 0..<p.len - 1:
+            if not matches(c, p[i], n[i]): return
+          if p.len == n.len and lastSon(n).kind == nkHiddenStdConv and
+              lastSon(n)[1].kind == nkBracket:
             # unpack varargs:
-            let n = lastSon(n).sons[1]
+            let n = lastSon(n)[1]
             arglist = newNodeI(nkArgList, n.info, n.len)
-            for i in 0..<n.len: arglist.sons[i] = n.sons[i]
+            for i in 0..<n.len: arglist[i] = n[i]
           else:
-            arglist = newNodeI(nkArgList, n.info, len(n) - plen + 1)
+            arglist = newNodeI(nkArgList, n.info, n.len - p.len + 1)
             # f(1, 2, 3)
             # p(X)
-            for i in 0 .. len(n) - plen:
-              arglist.sons[i] = n.sons[i + plen - 1]
+            for i in 0..n.len - p.len:
+              arglist[i] = n[i + p.len - 1]
           return bindOrCheck(c, v.sym, arglist)
-        elif plen-1 == len(n):
-          for i in 0 .. plen - 2:
-            if not matches(c, p.sons[i], n.sons[i]): return
+        elif p.len-1 == n.len:
+          for i in 0..<p.len - 1:
+            if not matches(c, p[i], n[i]): return
           arglist = newNodeI(nkArgList, n.info)
           return bindOrCheck(c, v.sym, arglist)
-      if plen == len(n):
-        for i in 0 ..< len(p):
-          if not matches(c, p.sons[i], n.sons[i]): return
+      if p.len == n.len:
+        for i in 0..<p.len:
+          if not matches(c, p[i], n[i]): return
         result = true
 
 proc matchStmtList(c: PPatternContext, p, n: PNode): PNode =
   proc matchRange(c: PPatternContext, p, n: PNode, i: int): bool =
-    for j in 0 ..< p.len:
-      if not matches(c, p.sons[j], n.sons[i+j]):
+    for j in 0..<p.len:
+      if not matches(c, p[j], n[i+j]):
         # we need to undo any bindings:
         when defined(nimNoNilSeqs):
           c.mapping = @[]
@@ -222,36 +221,36 @@ proc matchStmtList(c: PPatternContext, p, n: PNode): PNode =
   if p.kind == nkStmtList and n.kind == p.kind and p.len < n.len:
     let n = flattenStmts(n)
     # no need to flatten 'p' here as that has already been done
-    for i in 0 .. n.len - p.len:
+    for i in 0..n.len - p.len:
       if matchRange(c, p, n, i):
         c.subMatch = true
         result = newNodeI(nkStmtList, n.info, 3)
-        result.sons[0] = extractRange(nkStmtList, n, 0, i-1)
-        result.sons[1] = extractRange(nkStmtList, n, i, i+p.len-1)
-        result.sons[2] = extractRange(nkStmtList, n, i+p.len, n.len-1)
+        result[0] = extractRange(nkStmtList, n, 0, i-1)
+        result[1] = extractRange(nkStmtList, n, i, i+p.len-1)
+        result[2] = extractRange(nkStmtList, n, i+p.len, n.len-1)
         break
   elif matches(c, p, n):
     result = n
 
 proc aliasAnalysisRequested(params: PNode): bool =
   if params.len >= 2:
-    for i in 1 ..< params.len:
-      let param = params.sons[i].sym
+    for i in 1..<params.len:
+      let param = params[i].sym
       if whichAlias(param) != aqNone: return true
 
 proc addToArgList(result, n: PNode) =
   if n.typ != nil and n.typ.kind != tyTyped:
     if n.kind != nkArgList: result.add(n)
     else:
-      for i in 0 ..< n.len: result.add(n.sons[i])
+      for i in 0..<n.len: result.add(n[i])
 
 proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
   ## returns a tree to semcheck if the rule triggered; nil otherwise
   var ctx: TPatternContext
   ctx.owner = s
   ctx.c = c
-  ctx.formals = len(s.typ)-1
-  var m = matchStmtList(ctx, s.ast.sons[patternPos], n)
+  ctx.formals = s.typ.len-1
+  var m = matchStmtList(ctx, s.ast[patternPos], n)
   if isNil(m): return nil
   # each parameter should have been bound; we simply setup a call and
   # let semantic checking deal with the rest :-)
@@ -262,8 +261,8 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
   var args: PNode
   if requiresAA:
     args = newNodeI(nkArgList, n.info)
-  for i in 1 ..< params.len:
-    let param = params.sons[i].sym
+  for i in 1..<params.len:
+    let param = params[i].sym
     let x = getLazy(ctx, param)
     # couldn't bind parameter:
     if isNil(x): return nil
@@ -271,9 +270,9 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
     if requiresAA: addToArgList(args, x)
   # perform alias analysis here:
   if requiresAA:
-    for i in 1 ..< params.len:
-      var rs = result.sons[i]
-      let param = params.sons[i].sym
+    for i in 1..<params.len:
+      var rs = result[i]
+      let param = params[i].sym
       case whichAlias(param)
       of aqNone: discard
       of aqShouldAlias:
@@ -298,5 +297,5 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
   markUsed(c, n.info, s)
   if ctx.subMatch:
     assert m.len == 3
-    m.sons[1] = result
+    m[1] = result
     result = m
diff --git a/compiler/platform.nim b/compiler/platform.nim
index 5b9c0450d..c5d1ac6f3 100644
--- a/compiler/platform.nim
+++ b/compiler/platform.nim
@@ -242,23 +242,23 @@ proc setTarget*(t: var Target; o: TSystemOS, c: TSystemCPU) =
   t.tnl = OS[o].newLine
 
 proc nameToOS*(name: string): TSystemOS =
-  for i in succ(osNone) .. high(TSystemOS):
+  for i in succ(osNone)..high(TSystemOS):
     if cmpIgnoreStyle(name, OS[i].name) == 0:
       return i
   result = osNone
 
 proc listOSnames*(): seq[string] =
-  for i in succ(osNone) .. high(TSystemOS):
+  for i in succ(osNone)..high(TSystemOS):
     result.add OS[i].name
 
 proc nameToCPU*(name: string): TSystemCPU =
-  for i in succ(cpuNone) .. high(TSystemCPU):
+  for i in succ(cpuNone)..high(TSystemCPU):
     if cmpIgnoreStyle(name, CPU[i].name) == 0:
       return i
   result = cpuNone
 
 proc listCPUnames*(): seq[string] =
-  for i in succ(cpuNone) .. high(TSystemCPU):
+  for i in succ(cpuNone)..high(TSystemCPU):
     result.add CPU[i].name
 
 proc setTargetFromSystem*(t: var Target) =
diff --git a/compiler/plugins/itersgen.nim b/compiler/plugins/itersgen.nim
index e4b3a5029..61dda62af 100644
--- a/compiler/plugins/itersgen.nim
+++ b/compiler/plugins/itersgen.nim
@@ -42,5 +42,5 @@ proc iterToProcImpl*(c: PContext, n: PNode): PNode =
               pattern = c.graph.emptyNode, genericParams = c.graph.emptyNode,
               pragmas = orig[pragmasPos], exceptions = c.graph.emptyNode)
 
-  prc.ast.add iter.sym.ast.sons[resultPos]
+  prc.ast.add iter.sym.ast[resultPos]
   addInterfaceDecl(c, prc)
diff --git a/compiler/plugins/locals.nim b/compiler/plugins/locals.nim
index 73f6eaa19..f3ee94547 100644
--- a/compiler/plugins/locals.nim
+++ b/compiler/plugins/locals.nim
@@ -32,7 +32,7 @@ proc semLocals*(c: PContext, n: PNode): PNode =
           field.position = counter
           inc(counter)
 
-          addSon(tupleType.n, newSymNode(field))
+          tupleType.n.add newSymNode(field)
           addSonSkipIntLit(tupleType, field.typ)
 
           var a = newSymNode(it, result.info)
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index ad58c0bd8..a04eafee9 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -107,12 +107,12 @@ proc illegalCustomPragma*(c: PContext, n: PNode, s: PSym) =
 proc pragmaAsm*(c: PContext, n: PNode): char =
   result = '\0'
   if n != nil:
-    for i in 0 ..< len(n):
-      let it = n.sons[i]
-      if it.kind in nkPragmaCallKinds and it.len == 2 and it.sons[0].kind == nkIdent:
-        case whichKeyword(it.sons[0].ident)
+    for i in 0..<n.len:
+      let it = n[i]
+      if it.kind in nkPragmaCallKinds and it.len == 2 and it[0].kind == nkIdent:
+        case whichKeyword(it[0].ident)
         of wSubsChar:
-          if it.sons[1].kind == nkCharLit: result = chr(int(it.sons[1].intVal))
+          if it[1].kind == nkCharLit: result = chr(int(it[1].intVal))
           else: invalidPragma(c, it)
         else: invalidPragma(c, it)
       else:
@@ -176,9 +176,9 @@ proc getStrLitNode(c: PContext, n: PNode): PNode =
     # error correction:
     result = newEmptyStrNode(c, n)
   else:
-    n.sons[1] = c.semConstExpr(c, n.sons[1])
-    case n.sons[1].kind
-    of nkStrLit, nkRStrLit, nkTripleStrLit: result = n.sons[1]
+    n[1] = c.semConstExpr(c, n[1])
+    case n[1].kind
+    of nkStrLit, nkRStrLit, nkTripleStrLit: result = n[1]
     else:
       localError(c.config, n.info, errStringLiteralExpected)
       # error correction:
@@ -191,9 +191,9 @@ proc expectIntLit(c: PContext, n: PNode): int =
   if n.kind notin nkPragmaCallKinds or n.len != 2:
     localError(c.config, n.info, errIntLiteralExpected)
   else:
-    n.sons[1] = c.semConstExpr(c, n.sons[1])
-    case n.sons[1].kind
-    of nkIntLit..nkInt64Lit: result = int(n.sons[1].intVal)
+    n[1] = c.semConstExpr(c, n[1])
+    case n[1].kind
+    of nkIntLit..nkInt64Lit: result = int(n[1].intVal)
     else: localError(c.config, n.info, errIntLiteralExpected)
 
 proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string =
@@ -210,9 +210,9 @@ proc processMagic(c: PContext, n: PNode, s: PSym) =
     localError(c.config, n.info, errStringLiteralExpected)
     return
   var v: string
-  if n.sons[1].kind == nkIdent: v = n.sons[1].ident.s
+  if n[1].kind == nkIdent: v = n[1].ident.s
   else: v = expectStrLit(c, n)
-  for m in low(TMagic) .. high(TMagic):
+  for m in low(TMagic)..high(TMagic):
     if substr($m, 1) == v:
       s.magic = m
       break
@@ -225,8 +225,8 @@ proc wordToCallConv(sw: TSpecialWord): TCallingConvention =
 
 proc isTurnedOn(c: PContext, n: PNode): bool =
   if n.kind in nkPragmaCallKinds and n.len == 2:
-    let x = c.semConstBoolExpr(c, n.sons[1])
-    n.sons[1] = x
+    let x = c.semConstBoolExpr(c, n[1])
+    n[1] = x
     if x.kind == nkIntLit: return x.intVal != 0
   localError(c.config, n.info, "'on' or 'off' expected")
 
@@ -248,8 +248,8 @@ proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) =
           (if flag == sfNoForward: "{.noForward.}" else: "{.reorder.}") & " is deprecated")
 
 proc processCallConv(c: PContext, n: PNode) =
-  if n.kind in nkPragmaCallKinds and n.len == 2 and n.sons[1].kind == nkIdent:
-    let sw = whichKeyword(n.sons[1].ident)
+  if n.kind in nkPragmaCallKinds and n.len == 2 and n[1].kind == nkIdent:
+    let sw = whichKeyword(n[1].ident)
     case sw
     of FirstCallConv..LastCallConv:
       c.optionStack[^1].defaultCC = wordToCallConv(sw)
@@ -276,7 +276,7 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode =
   else:
     # For the OpenGL wrapper we support:
     # {.dynlib: myGetProcAddr(...).}
-    result = c.semExpr(c, n.sons[1])
+    result = c.semExpr(c, n[1])
     if result.kind == nkSym and result.sym.kind == skConst:
       result = result.sym.ast # look it up
     if result.typ == nil or result.typ.kind notin {tyPointer, tyString, tyProc}:
@@ -304,7 +304,7 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) =
       sym.typ.callConv = ccCDecl
 
 proc processNote(c: PContext, n: PNode) =
-  if n.kind in nkPragmaCallKinds and len(n) == 2 and
+  if n.kind in nkPragmaCallKinds and n.len == 2 and
       n[0].kind == nkBracketExpr and
       n[0].len == 2 and
       n[0][1].kind == nkIdent and n[0][0].kind == nkIdent:
@@ -323,7 +323,7 @@ proc processNote(c: PContext, n: PNode) =
       return
 
     let x = c.semConstBoolExpr(c, n[1])
-    n.sons[1] = x
+    n[1] = x
     if x.kind == nkIntLit and x.intVal != 0: incl(c.config.notes, nk)
     else: excl(c.config.notes, nk)
   else:
@@ -379,10 +379,10 @@ proc processExperimental(c: PContext; n: PNode) =
 proc tryProcessOption(c: PContext, n: PNode, resOptions: var TOptions): bool =
   result = true
   if n.kind notin nkPragmaCallKinds or n.len != 2: result = false
-  elif n.sons[0].kind == nkBracketExpr: processNote(c, n)
-  elif n.sons[0].kind != nkIdent: result = false
+  elif n[0].kind == nkBracketExpr: processNote(c, n)
+  elif n[0].kind != nkIdent: result = false
   else:
-    let sw = whichKeyword(n.sons[0].ident)
+    let sw = whichKeyword(n[0].ident)
     if sw == wExperimental:
       processExperimental(c, n)
       return true
@@ -394,10 +394,10 @@ proc tryProcessOption(c: PContext, n: PNode, resOptions: var TOptions): bool =
       of wCallconv: processCallConv(c, n)
       of wDynlib: processDynLib(c, n, nil)
       of wOptimization:
-        if n.sons[1].kind != nkIdent:
+        if n[1].kind != nkIdent:
           invalidPragma(c, n)
         else:
-          case n.sons[1].ident.s.normalize
+          case n[1].ident.s.normalize
           of "speed":
             incl(resOptions, optOptimizeSpeed)
             excl(resOptions, optOptimizeSize)
@@ -416,15 +416,15 @@ proc processOption(c: PContext, n: PNode, resOptions: var TOptions) =
     localError(c.config, n.info, "option expected")
 
 proc processPush(c: PContext, n: PNode, start: int) =
-  if n.sons[start-1].kind in nkPragmaCallKinds:
+  if n[start-1].kind in nkPragmaCallKinds:
     localError(c.config, n.info, "'push' cannot have arguments")
   var x = pushOptionEntry(c)
-  for i in start ..< len(n):
-    if not tryProcessOption(c, n.sons[i], c.config.options):
+  for i in start..<n.len:
+    if not tryProcessOption(c, n[i], c.config.options):
       # simply store it somewhere:
       if x.otherPragmas.isNil:
         x.otherPragmas = newNodeI(nkPragma, n.info)
-      x.otherPragmas.add n.sons[i]
+      x.otherPragmas.add n[i]
     #localError(c.config, n.info, errOptionExpected)
 
   # If stacktrace is disabled globally we should not enable it
@@ -474,7 +474,7 @@ proc processCompile(c: PContext, n: PNode) =
     recordPragma(c, it, "compile", src.string, dest.string)
 
   proc getStrLit(c: PContext, n: PNode; i: int): string =
-    n.sons[i] = c.semConstExpr(c, n[i])
+    n[i] = c.semConstExpr(c, n[i])
     case n[i].kind
     of nkStrLit, nkRStrLit, nkTripleStrLit:
       shallowCopy(result, n[i].strVal)
@@ -482,7 +482,7 @@ proc processCompile(c: PContext, n: PNode) =
       localError(c.config, n.info, errStringLiteralExpected)
       result = ""
 
-  let it = if n.kind in nkPragmaCallKinds and n.len == 2: n.sons[1] else: n
+  let it = if n.kind in nkPragmaCallKinds and n.len == 2: n[1] else: n
   if it.kind in {nkPar, nkTupleConstr} and it.len == 2:
     let s = getStrLit(c, it, 0)
     let dest = getStrLit(c, it, 1)
@@ -507,10 +507,10 @@ proc processLink(c: PContext, n: PNode) =
   recordPragma(c, n, "link", found.string)
 
 proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
-  case n.sons[1].kind
+  case n[1].kind
   of nkStrLit, nkRStrLit, nkTripleStrLit:
     result = newNode(if n.kind == nkAsmStmt: nkAsmStmt else: nkArgList, n.info)
-    var str = n.sons[1].strVal
+    var str = n[1].strVal
     if str == "":
       localError(con.config, n.info, "empty 'asm' statement")
       return
@@ -519,7 +519,7 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
     while true:
       var b = strutils.find(str, marker, a)
       var sub = if b < 0: substr(str, a) else: substr(str, a, b - 1)
-      if sub != "": addSon(result, newStrNode(nkStrLit, sub))
+      if sub != "": result.add newStrNode(nkStrLit, sub)
       if b < 0: break
       var c = strutils.find(str, marker, b + 1)
       if c < 0: sub = substr(str, b + 1)
@@ -530,12 +530,12 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
           when false:
             if e.kind == skStub: loadStub(e)
           incl(e.flags, sfUsed)
-          addSon(result, newSymNode(e))
+          result.add newSymNode(e)
         else:
-          addSon(result, newStrNode(nkStrLit, sub))
+          result.add newStrNode(nkStrLit, sub)
       else:
         # an empty '``' produces a single '`'
-        addSon(result, newStrNode(nkStrLit, $marker))
+        result.add newStrNode(nkStrLit, $marker)
       if c < 0: break
       a = c + 1
   else:
@@ -550,13 +550,13 @@ proc pragmaEmit(c: PContext, n: PNode) =
     if n1.kind == nkBracket:
       var b = newNodeI(nkBracket, n1.info, n1.len)
       for i in 0..<n1.len:
-        b.sons[i] = c.semExpr(c, n1[i])
-      n.sons[1] = b
+        b[i] = c.semExpr(c, n1[i])
+      n[1] = b
     else:
-      n.sons[1] = c.semConstExpr(c, n1)
-      case n.sons[1].kind
+      n[1] = c.semConstExpr(c, n1)
+      case n[1].kind
       of nkStrLit, nkRStrLit, nkTripleStrLit:
-        n.sons[1] = semAsmOrEmit(c, n, '`')
+        n[1] = semAsmOrEmit(c, n, '`')
       else:
         localError(c.config, n.info, errStringLiteralExpected)
 
@@ -569,20 +569,20 @@ proc pragmaUnroll(c: PContext, n: PNode) =
   elif n.kind in nkPragmaCallKinds and n.len == 2:
     var unrollFactor = expectIntLit(c, n)
     if unrollFactor <% 32:
-      n.sons[1] = newIntNode(nkIntLit, unrollFactor)
+      n[1] = newIntNode(nkIntLit, unrollFactor)
     else:
       invalidPragma(c, n)
 
 proc pragmaLine(c: PContext, n: PNode) =
   if n.kind in nkPragmaCallKinds and n.len == 2:
-    n.sons[1] = c.semConstExpr(c, n.sons[1])
-    let a = n.sons[1]
+    n[1] = c.semConstExpr(c, n[1])
+    let a = n[1]
     if a.kind in {nkPar, nkTupleConstr}:
       # unpack the tuple
-      var x = a.sons[0]
-      var y = a.sons[1]
-      if x.kind == nkExprColonExpr: x = x.sons[1]
-      if y.kind == nkExprColonExpr: y = y.sons[1]
+      var x = a[0]
+      var y = a[1]
+      if x.kind == nkExprColonExpr: x = x[1]
+      if y.kind == nkExprColonExpr: y = y[1]
       if x.kind != nkStrLit:
         localError(c.config, n.info, errStringLiteralExpected)
       elif y.kind != nkIntLit:
@@ -614,7 +614,7 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) =
     x.typ = t
 
   if n.kind in nkPragmaCallKinds and n.len == 2:
-    let it = n.sons[1]
+    let it = n[1]
     if it.kind notin {nkCurly, nkBracket}:
       processExc(c, it)
     else:
@@ -630,8 +630,8 @@ proc pragmaLockStmt(c: PContext; it: PNode) =
     if n.kind != nkBracket:
       localError(c.config, n.info, errGenerated, "locks pragma takes a list of expressions")
     else:
-      for i in 0 ..< n.len:
-        n.sons[i] = c.semExpr(c, n.sons[i])
+      for i in 0..<n.len:
+        n[i] = c.semExpr(c, n[i])
 
 proc pragmaLocks(c: PContext, it: PNode): TLockLevel =
   if it.kind notin nkPragmaCallKinds or it.len != 2:
@@ -652,7 +652,7 @@ proc pragmaLocks(c: PContext, it: PNode): TLockLevel =
 
 proc typeBorrow(c: PContext; sym: PSym, n: PNode) =
   if n.kind in nkPragmaCallKinds and n.len == 2:
-    let it = n.sons[1]
+    let it = n[1]
     if it.kind != nkAccQuoted:
       localError(c.config, n.info, "a type can only borrow `.` for now")
   incl(sym.typ.flags, tfBorrowDot)
@@ -684,7 +684,7 @@ proc deprecatedStmt(c: PContext; outerPragma: PNode) =
       incl(alias.flags, sfExported)
       if sfCompilerProc in dest.flags: markCompilerProc(c, alias)
       addInterfaceDecl(c, alias)
-      n.sons[1] = newSymNode(dest)
+      n[1] = newSymNode(dest)
     else:
       localError(c.config, n.info, "key:value pair expected")
 
@@ -739,13 +739,13 @@ proc semCustomPragma(c: PContext, n: PNode): PNode =
 proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
                   validPragmas: TSpecialWords,
                   comesFromPush, isStatement: bool): bool =
-  var it = n.sons[i]
-  var key = if it.kind in nkPragmaCallKinds and it.len > 1: it.sons[0] else: it
+  var it = n[i]
+  var key = if it.kind in nkPragmaCallKinds and it.len > 1: it[0] else: it
   if key.kind == nkBracketExpr:
     processNote(c, it)
     return
   elif key.kind notin nkIdentKinds:
-    n.sons[i] = semCustomPragma(c, it)
+    n[i] = semCustomPragma(c, it)
     return
   let ident = considerQuotedIdent(c, key)
   var userPragma = strTableGet(c.userPragmas, ident)
@@ -1108,7 +1108,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
         if it.kind notin nkPragmaCallKinds or it.len != 2:
           localError(c.config, it.info, "expression expected")
         else:
-          it.sons[1] = c.semExpr(c, it.sons[1])
+          it[1] = c.semExpr(c, it[1])
       of wExperimental:
         if not isTopLevel(c):
           localError(c.config, n.info, "'experimental' pragma only valid as toplevel statement or in a 'push' environment")
@@ -1144,7 +1144,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
     else:
       if sym == nil or (sym.kind in {skVar, skLet, skParam,
                         skField, skProc, skFunc, skConverter, skMethod, skType}):
-        n.sons[i] = semCustomPragma(c, it)
+        n[i] = semCustomPragma(c, it)
       elif sym != nil:
         illegalCustomPragma(c, it, sym)
       else:
@@ -1152,7 +1152,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
 
 proc overwriteLineInfo(n: PNode; info: TLineInfo) =
   n.info = info
-  for i in 0..<safeLen(n):
+  for i in 0..<n.safeLen:
     overwriteLineInfo(n[i], info)
 
 proc mergePragmas(n, pragmas: PNode) =
@@ -1161,7 +1161,7 @@ proc mergePragmas(n, pragmas: PNode) =
   if n[pragmasPos].kind == nkEmpty:
     n[pragmasPos] = pragmas
   else:
-    for p in pragmas: n.sons[pragmasPos].add p
+    for p in pragmas: n[pragmasPos].add p
 
 proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
                       validPragmas: TSpecialWords) =
diff --git a/compiler/prefixmatches.nim b/compiler/prefixmatches.nim
index 246d1ae5e..b03d1d76e 100644
--- a/compiler/prefixmatches.nim
+++ b/compiler/prefixmatches.nim
@@ -20,14 +20,13 @@ proc prefixMatch*(p, s: string): PrefixMatch =
   template eq(a, b): bool = a.toLowerAscii == b.toLowerAscii
   if p.len > s.len: return PrefixMatch.None
   var i = 0
-  let L = s.len
   # check for prefix/contains:
-  while i < L:
+  while i < s.len:
     if s[i] == '_': inc i
-    if i < L and eq(s[i], p[0]):
+    if i < s.len and eq(s[i], p[0]):
       var ii = i+1
       var jj = 1
-      while ii < L and jj < p.len:
+      while ii < s.len and jj < p.len:
         if p[jj] == '_': inc jj
         if s[ii] == '_': inc ii
         if not eq(s[ii], p[jj]): break
diff --git a/compiler/procfind.nim b/compiler/procfind.nim
index 7e8cd3b8a..f7dc6c379 100644
--- a/compiler/procfind.nim
+++ b/compiler/procfind.nim
@@ -14,14 +14,14 @@ import
   ast, astalgo, msgs, semdata, types, trees, strutils
 
 proc equalGenericParams(procA, procB: PNode): bool =
-  if len(procA) != len(procB): return false
-  for i in 0 ..< len(procA):
-    if procA.sons[i].kind != nkSym:
+  if procA.len != procB.len: return false
+  for i in 0..<procA.len:
+    if procA[i].kind != nkSym:
       return false
-    if procB.sons[i].kind != nkSym:
+    if procB[i].kind != nkSym:
       return false
-    let a = procA.sons[i].sym
-    let b = procB.sons[i].sym
+    let a = procA[i].sym
+    let b = procB[i].sym
     if a.name.id != b.name.id or
         not sameTypeOrNil(a.typ, b.typ, {ExactTypeDescValues}): return
     if a.ast != nil and b.ast != nil:
@@ -40,11 +40,11 @@ proc searchForProcOld*(c: PContext, scope: PScope, fn: PSym): PSym =
     # not kept in the AST ..
     while result != nil:
       if result.kind == fn.kind and isGenericRoutine(result):
-        let genR = result.ast.sons[genericParamsPos]
-        let genF = fn.ast.sons[genericParamsPos]
+        let genR = result.ast[genericParamsPos]
+        let genF = fn.ast[genericParamsPos]
         if exprStructuralEquivalent(genR, genF) and
-           exprStructuralEquivalent(result.ast.sons[paramsPos],
-                                    fn.ast.sons[paramsPos]) and
+           exprStructuralEquivalent(result.ast[paramsPos],
+                                    fn.ast[paramsPos]) and
            equalGenericParams(genR, genF):
             return
       result = nextIdentIter(it, scope.symbols)
@@ -95,15 +95,14 @@ proc searchForProc*(c: PContext, scope: PScope, fn: PSym): PSym =
 
 when false:
   proc paramsFitBorrow(child, parent: PNode): bool =
-    var length = len(child)
     result = false
-    if length == len(parent):
-      for i in 1 ..< length:
-        var m = child.sons[i].sym
-        var n = parent.sons[i].sym
+    if child.len == parent.len:
+      for i in 1..<child.len:
+        var m = child[i].sym
+        var n = parent[i].sym
         assert((m.kind == skParam) and (n.kind == skParam))
         if not compareTypes(m.typ, n.typ, dcEqOrDistinctOf): return
-      if not compareTypes(child.sons[0].typ, parent.sons[0].typ,
+      if not compareTypes(child[0].typ, parent[0].typ,
                           dcEqOrDistinctOf): return
       result = true
 
@@ -116,7 +115,7 @@ when false:
       while result != nil:
         # watchout! result must not be the same as fn!
         if (result.Kind == fn.kind) and (result.id != fn.id):
-          if equalGenericParams(result.ast.sons[genericParamsPos],
-                                fn.ast.sons[genericParamsPos]):
+          if equalGenericParams(result.ast[genericParamsPos],
+                                fn.ast[genericParamsPos]):
             if paramsFitBorrow(fn.typ.n, result.typ.n): return
         result = NextIdentIter(it, scope.symbols)
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index dc6ff93c0..698d84de6 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -82,7 +82,7 @@ when defined(nimpretty):
       result = (n.info.line.int, n.info.line.int + countLines(n.comment))
     else:
       result = (n.info.line.int, n.info.line.int)
-    for i in 0 ..< safeLen(n):
+    for i in 0..<n.safeLen:
       let (currMin, currMax) = minmaxLine(n[i])
       if currMin < result[0]: result[0] = currMin
       if currMax > result[1]: result[1] = currMax
@@ -109,12 +109,11 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags; config: ConfigRef) =
   g.config = config
 
 proc addTok(g: var TSrcGen, kind: TTokType, s: string; sym: PSym = nil) =
-  var length = len(g.tokens)
-  setLen(g.tokens, length + 1)
-  g.tokens[length].kind = kind
-  g.tokens[length].length = int16(len(s))
-  g.tokens[length].sym = sym
-  add(g.buf, s)
+  setLen(g.tokens, g.tokens.len + 1)
+  g.tokens[^1].kind = kind
+  g.tokens[^1].length = int16(s.len)
+  g.tokens[^1].sym = sym
+  g.buf.add(s)
 
 proc addPendingNL(g: var TSrcGen) =
   if g.pendingNL >= 0:
@@ -172,17 +171,17 @@ proc dedent(g: var TSrcGen) =
 proc put(g: var TSrcGen, kind: TTokType, s: string; sym: PSym = nil) =
   if kind != tkSpaces:
     addPendingNL(g)
-    if len(s) > 0:
+    if s.len > 0:
       addTok(g, kind, s, sym)
-      inc(g.lineLen, len(s))
+      inc(g.lineLen, s.len)
   else:
     g.pendingWhitespace = s.len
 
 proc putComment(g: var TSrcGen, s: string) =
   if s.len == 0: return
   var i = 0
-  let hi = len(s) - 1
-  var isCode = (len(s) >= 2) and (s[1] != ' ')
+  let hi = s.len - 1
+  var isCode = (s.len >= 2) and (s[1] != ' ')
   var ind = g.lineLen
   var com = "## "
   while i <= hi:
@@ -201,7 +200,7 @@ proc putComment(g: var TSrcGen, s: string) =
       inc(i)
       optNL(g, ind)
     of ' ', '\x09':
-      add(com, s[i])
+      com.add(s[i])
       inc(i)
     else:
       # we may break the comment into a multi-line comment if the line
@@ -214,7 +213,7 @@ proc putComment(g: var TSrcGen, s: string) =
         optNL(g, ind)
         com = "## "
       while i <= hi and s[i] > ' ':
-        add(com, s[i])
+        com.add(s[i])
         inc(i)
   put(g, tkComment, com)
   optNL(g)
@@ -222,7 +221,7 @@ proc putComment(g: var TSrcGen, s: string) =
 proc maxLineLength(s: string): int =
   if s.len == 0: return 0
   var i = 0
-  let hi = len(s) - 1
+  let hi = s.len - 1
   var lineLen = 0
   while i <= hi:
     case s[i]
@@ -243,7 +242,7 @@ proc maxLineLength(s: string): int =
 
 proc putRawStr(g: var TSrcGen, kind: TTokType, s: string) =
   var i = 0
-  let hi = len(s) - 1
+  let hi = s.len - 1
   var str = ""
   while i <= hi:
     case s[i]
@@ -259,12 +258,12 @@ proc putRawStr(g: var TSrcGen, kind: TTokType, s: string) =
       inc(i)
       optNL(g, 0)
     else:
-      add(str, s[i])
+      str.add(s[i])
       inc(i)
   put(g, kind, str)
 
 proc containsNL(s: string): bool =
-  for i in 0 ..< len(s):
+  for i in 0..<s.len:
     case s[i]
     of '\x0D', '\x0A':
       return true
@@ -273,9 +272,8 @@ proc containsNL(s: string): bool =
   result = false
 
 proc pushCom(g: var TSrcGen, n: PNode) =
-  var length = len(g.comStack)
-  setLen(g.comStack, length + 1)
-  g.comStack[length] = n
+  setLen(g.comStack, g.comStack.len + 1)
+  g.comStack[^1] = n
 
 proc popAllComs(g: var TSrcGen) =
   setLen(g.comStack, 0)
@@ -292,11 +290,11 @@ proc shouldRenderComment(g: var TSrcGen, n: PNode): bool =
 proc gcom(g: var TSrcGen, n: PNode) =
   assert(n != nil)
   if shouldRenderComment(g, n):
-    if (g.pendingNL < 0) and (len(g.buf) > 0) and (g.buf[len(g.buf)-1] != ' '):
+    if (g.pendingNL < 0) and (g.buf.len > 0) and (g.buf[^1] != ' '):
       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
+    if (g.pendingNL < 0) and (g.buf.len > 0) and
         (g.lineLen < LineCommentColumn):
       var ml = maxLineLength(n.comment)
       if ml + LineCommentColumn <= MaxLineLen:
@@ -304,7 +302,7 @@ proc gcom(g: var TSrcGen, n: PNode) =
     putComment(g, n.comment)  #assert(g.comStack[high(g.comStack)] = n);
 
 proc gcoms(g: var TSrcGen) =
-  for i in 0 .. high(g.comStack): gcom(g, g.comStack[i])
+  for i in 0..high(g.comStack): gcom(g, g.comStack[i])
   popAllComs(g)
 
 proc lsub(g: TSrcGen; n: PNode): int
@@ -398,8 +396,8 @@ proc atom(g: TSrcGen; n: PNode): string =
 proc lcomma(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int =
   assert(theEnd < 0)
   result = 0
-  for i in start .. len(n) + theEnd:
-    let param = n.sons[i]
+  for i in start..n.len + theEnd:
+    let param = n[i]
     if nfDefaultParam notin param.flags:
       inc(result, lsub(g, param))
       inc(result, 2)          # for ``, ``
@@ -409,7 +407,7 @@ proc lcomma(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int =
 proc lsons(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int =
   assert(theEnd < 0)
   result = 0
-  for i in start .. len(n) + theEnd: inc(result, lsub(g, n.sons[i]))
+  for i in start..n.len + theEnd: inc(result, lsub(g, n[i]))
 
 proc lsub(g: TSrcGen; n: PNode): int =
   # computes the length of a tree
@@ -419,17 +417,17 @@ proc lsub(g: TSrcGen; n: PNode): int =
   of nkEmpty: result = 0
   of nkTripleStrLit:
     if containsNL(n.strVal): result = MaxLineLen + 1
-    else: result = len(atom(g, n))
+    else: result = atom(g, n).len
   of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit:
-    result = len(atom(g, n))
+    result = atom(g, n).len
   of nkCall, nkBracketExpr, nkCurlyExpr, nkConv, nkPattern, nkObjConstr:
-    result = lsub(g, n.sons[0]) + lcomma(g, n, 1) + 2
+    result = lsub(g, n[0]) + lcomma(g, n, 1) + 2
   of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: result = lsub(g, n[1])
-  of nkCast: result = lsub(g, n.sons[0]) + lsub(g, n.sons[1]) + len("cast[]()")
-  of nkAddr: result = (if n.len>0: lsub(g, n.sons[0]) + len("addr()") else: 4)
-  of nkStaticExpr: result = lsub(g, n.sons[0]) + len("static_")
-  of nkHiddenAddr, nkHiddenDeref, nkStringToCString, nkCStringToString: result = lsub(g, n.sons[0])
-  of nkCommand: result = lsub(g, n.sons[0]) + lcomma(g, n, 1) + 1
+  of nkCast: result = lsub(g, n[0]) + lsub(g, n[1]) + len("cast[]()")
+  of nkAddr: result = (if n.len>0: lsub(g, n[0]) + len("addr()") else: 4)
+  of nkStaticExpr: result = lsub(g, n[0]) + len("static_")
+  of nkHiddenAddr, nkHiddenDeref, nkStringToCString, nkCStringToString: result = lsub(g, n[0])
+  of nkCommand: result = lsub(g, n[0]) + lcomma(g, n, 1) + 1
   of nkExprEqExpr, nkAsgn, nkFastAsgn: result = lsons(g, n) + 3
   of nkPar, nkCurly, nkBracket, nkClosure: result = lcomma(g, n) + 2
   of nkTupleConstr:
@@ -439,93 +437,92 @@ proc lsub(g: TSrcGen; n: PNode): int =
   of nkTableConstr:
     result = if n.len > 0: lcomma(g, n) + 2 else: len("{:}")
   of nkClosedSymChoice, nkOpenSymChoice:
-    result = lsons(g, n) + len("()") + len(n) - 1
+    result = lsons(g, n) + len("()") + n.len - 1
   of nkTupleTy: result = lcomma(g, n) + len("tuple[]")
   of nkTupleClassTy: result = len("tuple")
   of nkDotExpr: result = lsons(g, n) + 1
   of nkBind: result = lsons(g, n) + len("bind_")
   of nkBindStmt: result = lcomma(g, n) + len("bind_")
   of nkMixinStmt: result = lcomma(g, n) + len("mixin_")
-  of nkCheckedFieldExpr: result = lsub(g, n.sons[0])
+  of nkCheckedFieldExpr: result = lsub(g, n[0])
   of nkLambda: result = lsons(g, n) + len("proc__=_")
   of nkDo: result = lsons(g, n) + len("do__:_")
   of nkConstDef, nkIdentDefs:
     result = lcomma(g, n, 0, - 3)
-    var L = len(n)
-    if n.sons[L - 2].kind != nkEmpty: result = result + lsub(g, n.sons[L - 2]) + 2
-    if n.sons[L - 1].kind != nkEmpty: result = result + lsub(g, n.sons[L - 1]) + 3
+    if n[^2].kind != nkEmpty: result = result + lsub(g, n[^2]) + 2
+    if n[^1].kind != nkEmpty: result = result + lsub(g, n[^1]) + 3
   of nkVarTuple: result = lcomma(g, n, 0, - 3) + len("() = ") + lsub(g, lastSon(n))
   of nkChckRangeF: result = len("chckRangeF") + 2 + lcomma(g, n)
   of nkChckRange64: result = len("chckRange64") + 2 + lcomma(g, n)
   of nkChckRange: result = len("chckRange") + 2 + lcomma(g, n)
   of nkObjDownConv, nkObjUpConv:
     result = 2
-    if len(n) >= 1: result = result + lsub(g, n.sons[0])
+    if n.len >= 1: result = result + lsub(g, n[0])
     result = result + lcomma(g, n, 1)
   of nkExprColonExpr: result = lsons(g, n) + 2
   of nkInfix: result = lsons(g, n) + 2
   of nkPrefix:
-    result = lsons(g, n)+1+(if n.len > 0 and n.sons[1].kind == nkInfix: 2 else: 0)
+    result = lsons(g, n)+1+(if n.len > 0 and n[1].kind == nkInfix: 2 else: 0)
   of nkPostfix: result = lsons(g, n)
   of nkCallStrLit: result = lsons(g, n)
-  of nkPragmaExpr: result = lsub(g, n.sons[0]) + lcomma(g, n, 1)
+  of nkPragmaExpr: result = lsub(g, n[0]) + lcomma(g, n, 1)
   of nkRange: result = lsons(g, n) + 2
-  of nkDerefExpr: result = lsub(g, n.sons[0]) + 2
+  of nkDerefExpr: result = lsub(g, n[0]) + 2
   of nkAccQuoted: result = lsons(g, n) + 2
   of nkIfExpr:
-    result = lsub(g, n.sons[0].sons[0]) + lsub(g, n.sons[0].sons[1]) + lsons(g, n, 1) +
+    result = lsub(g, n[0][0]) + lsub(g, n[0][1]) + lsons(g, n, 1) +
         len("if_:_")
   of nkElifExpr: result = lsons(g, n) + len("_elif_:_")
-  of nkElseExpr: result = lsub(g, n.sons[0]) + len("_else:_") # type descriptions
-  of nkTypeOfExpr: result = (if n.len > 0: lsub(g, n.sons[0]) else: 0)+len("typeof()")
-  of nkRefTy: result = (if n.len > 0: lsub(g, n.sons[0])+1 else: 0) + len("ref")
-  of nkPtrTy: result = (if n.len > 0: lsub(g, n.sons[0])+1 else: 0) + len("ptr")
-  of nkVarTy: result = (if n.len > 0: lsub(g, n.sons[0])+1 else: 0) + len("var")
+  of nkElseExpr: result = lsub(g, n[0]) + len("_else:_") # type descriptions
+  of nkTypeOfExpr: result = (if n.len > 0: lsub(g, n[0]) else: 0)+len("typeof()")
+  of nkRefTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("ref")
+  of nkPtrTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("ptr")
+  of nkVarTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("var")
   of nkDistinctTy:
-    result = len("distinct") + (if n.len > 0: lsub(g, n.sons[0])+1 else: 0)
+    result = len("distinct") + (if n.len > 0: lsub(g, n[0])+1 else: 0)
     if n.len > 1:
       result += (if n[1].kind == nkWith: len("_with_") else: len("_without_"))
       result += lcomma(g, n[1])
-  of nkStaticTy: result = (if n.len > 0: lsub(g, n.sons[0]) else: 0) +
+  of nkStaticTy: result = (if n.len > 0: lsub(g, n[0]) else: 0) +
                                                          len("static[]")
   of nkTypeDef: result = lsons(g, n) + 3
-  of nkOfInherit: result = lsub(g, n.sons[0]) + len("of_")
+  of nkOfInherit: result = lsub(g, n[0]) + len("of_")
   of nkProcTy: result = lsons(g, n) + len("proc_")
   of nkIteratorTy: result = lsons(g, n) + len("iterator_")
   of nkSharedTy: result = lsons(g, n) + len("shared_")
   of nkEnumTy:
-    if len(n) > 0:
-      result = lsub(g, n.sons[0]) + lcomma(g, n, 1) + len("enum_")
+    if n.len > 0:
+      result = lsub(g, n[0]) + lcomma(g, n, 1) + len("enum_")
     else:
       result = len("enum")
   of nkEnumFieldDef: result = lsons(g, n) + 3
   of nkVarSection, nkLetSection:
-    if len(n) > 1: result = MaxLineLen + 1
+    if n.len > 1: result = MaxLineLen + 1
     else: result = lsons(g, n) + len("var_")
   of nkUsingStmt:
-    if len(n) > 1: result = MaxLineLen + 1
+    if n.len > 1: result = MaxLineLen + 1
     else: result = lsons(g, n) + len("using_")
   of nkReturnStmt:
     if n.len > 0 and n[0].kind == nkAsgn:
       result = len("return_") + lsub(g, n[0][1])
     else:
       result = len("return_") + lsub(g, n[0])
-  of nkRaiseStmt: result = lsub(g, n.sons[0]) + len("raise_")
-  of nkYieldStmt: result = lsub(g, n.sons[0]) + len("yield_")
-  of nkDiscardStmt: result = lsub(g, n.sons[0]) + len("discard_")
-  of nkBreakStmt: result = lsub(g, n.sons[0]) + len("break_")
-  of nkContinueStmt: result = lsub(g, n.sons[0]) + len("continue_")
+  of nkRaiseStmt: result = lsub(g, n[0]) + len("raise_")
+  of nkYieldStmt: result = lsub(g, n[0]) + len("yield_")
+  of nkDiscardStmt: result = lsub(g, n[0]) + len("discard_")
+  of nkBreakStmt: result = lsub(g, n[0]) + len("break_")
+  of nkContinueStmt: result = lsub(g, n[0]) + len("continue_")
   of nkPragma: result = lcomma(g, n) + 4
-  of nkCommentStmt: result = len(n.comment)
+  of nkCommentStmt: result = n.comment.len
   of nkOfBranch: result = lcomma(g, n, 0, - 2) + lsub(g, lastSon(n)) + len("of_:_")
-  of nkImportAs: result = lsub(g, n.sons[0]) + len("_as_") + lsub(g, n.sons[1])
+  of nkImportAs: result = lsub(g, n[0]) + len("_as_") + lsub(g, n[1])
   of nkElifBranch: result = lsons(g, n) + len("elif_:_")
-  of nkElse: result = lsub(g, n.sons[0]) + len("else:_")
-  of nkFinally: result = lsub(g, n.sons[0]) + len("finally:_")
+  of nkElse: result = lsub(g, n[0]) + len("else:_")
+  of nkFinally: result = lsub(g, n[0]) + len("finally:_")
   of nkGenericParams: result = lcomma(g, n) + 2
   of nkFormalParams:
     result = lcomma(g, n, 1) + 2
-    if n.sons[0].kind != nkEmpty: result = result + lsub(g, n.sons[0]) + 2
+    if n[0].kind != nkEmpty: result = result + lsub(g, n[0]) + 2
   of nkExceptBranch:
     result = lcomma(g, n, 0, -2) + lsub(g, lastSon(n)) + len("except_:_")
   else: result = MaxLineLen + 1
@@ -559,8 +556,8 @@ proc hasCom(n: PNode): bool =
   case n.kind
   of nkEmpty..nkNilLit: discard
   else:
-    for i in 0 ..< len(n):
-      if hasCom(n.sons[i]): return true
+    for i in 0..<n.len:
+      if hasCom(n[i]): return true
 
 proc putWithSpace(g: var TSrcGen, kind: TTokType, s: string) =
   put(g, kind, s)
@@ -568,16 +565,16 @@ proc putWithSpace(g: var TSrcGen, kind: TTokType, s: string) =
 
 proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0,
                theEnd: int = - 1, separator = tkComma) =
-  for i in start .. len(n) + theEnd:
-    var c = i < len(n) + theEnd
-    var sublen = lsub(g, n.sons[i]) + ord(c)
+  for i in start..n.len + theEnd:
+    var c = i < n.len + theEnd
+    var sublen = lsub(g, n[i]) + ord(c)
     if not fits(g, sublen) and (ind + sublen < MaxLineLen): optNL(g, ind)
     let oldLen = g.tokens.len
-    gsub(g, n.sons[i])
+    gsub(g, n[i])
     if c:
       if g.tokens.len > oldLen:
         putWithSpace(g, separator, TokTypeToStr[separator])
-      if hasCom(n.sons[i]):
+      if hasCom(n[i]):
         gcoms(g)
         optNL(g, ind)
 
@@ -603,17 +600,17 @@ proc gsemicolon(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) =
 
 proc gsons(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
            theEnd: int = - 1) =
-  for i in start .. len(n) + theEnd: gsub(g, n.sons[i], c)
+  for i in start..n.len + theEnd: gsub(g, n[i], c)
 
 proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TTokType,
               k: string) =
-  if len(n) == 0: return # empty var sections are possible
+  if n.len == 0: return # empty var sections are possible
   putWithSpace(g, kind, k)
   gcoms(g)
   indentNL(g)
-  for i in 0 ..< len(n):
+  for i in 0..<n.len:
     optNL(g)
-    gsub(g, n.sons[i], c)
+    gsub(g, n[i], c)
     gcoms(g)
   dedent(g)
 
@@ -621,8 +618,8 @@ proc longMode(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): bool =
   result = n.comment.len > 0
   if not result:
     # check further
-    for i in start .. len(n) + theEnd:
-      if (lsub(g, n.sons[i]) > MaxLineLen):
+    for i in start..n.len + theEnd:
+      if (lsub(g, n[i]) > MaxLineLen):
         result = true
         break
 
@@ -630,8 +627,7 @@ proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) =
   if n.kind == nkEmpty: return
   if n.kind in {nkStmtList, nkStmtListExpr, nkStmtListType}:
     if doIndent: indentNL(g)
-    let L = n.len
-    for i in 0 .. L-1:
+    for i in 0..<n.len:
       if i > 0:
         optNL(g, n[i-1], n[i])
       else:
@@ -659,34 +655,33 @@ proc gcond(g: var TSrcGen, n: PNode) =
 
 proc gif(g: var TSrcGen, n: PNode) =
   var c: TContext
-  gcond(g, n.sons[0].sons[0])
+  gcond(g, n[0][0])
   initContext(c)
   putWithSpace(g, tkColon, ":")
-  if longMode(g, n) or (lsub(g, n.sons[0].sons[1]) + g.lineLen > MaxLineLen):
+  if longMode(g, n) or (lsub(g, n[0][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 = len(n)
-  for i in 1 ..< length:
+  gstmts(g, n[0][1], c)
+  for i in 1..<n.len:
     optNL(g)
-    gsub(g, n.sons[i], c)
+    gsub(g, n[i], c)
 
 proc gwhile(g: var TSrcGen, n: PNode) =
   var c: TContext
   putWithSpace(g, tkWhile, "while")
-  gcond(g, n.sons[0])
+  gcond(g, n[0])
   putWithSpace(g, tkColon, ":")
   initContext(c)
-  if longMode(g, n) or (lsub(g, n.sons[1]) + g.lineLen > MaxLineLen):
+  if longMode(g, n) or (lsub(g, n[1]) + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcoms(g)                    # a good place for comments
-  gstmts(g, n.sons[1], c)
+  gstmts(g, n[1], c)
 
 proc gpattern(g: var TSrcGen, n: PNode) =
   var c: TContext
   put(g, tkCurlyLe, "{")
   initContext(c)
-  if longMode(g, n) or (lsub(g, n.sons[0]) + g.lineLen > MaxLineLen):
+  if longMode(g, n) or (lsub(g, n[0]) + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcoms(g)                    # a good place for comments
   gstmts(g, n, c)
@@ -694,58 +689,55 @@ proc gpattern(g: var TSrcGen, n: PNode) =
 
 proc gpragmaBlock(g: var TSrcGen, n: PNode) =
   var c: TContext
-  gsub(g, n.sons[0])
+  gsub(g, n[0])
   putWithSpace(g, tkColon, ":")
   initContext(c)
-  if longMode(g, n) or (lsub(g, n.sons[1]) + g.lineLen > MaxLineLen):
+  if longMode(g, n) or (lsub(g, n[1]) + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcoms(g)                    # a good place for comments
-  gstmts(g, n.sons[1], c)
+  gstmts(g, n[1], c)
 
 proc gtry(g: var TSrcGen, n: PNode) =
   var c: TContext
   put(g, tkTry, "try")
   putWithSpace(g, tkColon, ":")
   initContext(c)
-  if longMode(g, n) or (lsub(g, n.sons[0]) + g.lineLen > MaxLineLen):
+  if longMode(g, n) or (lsub(g, n[0]) + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcoms(g)                    # a good place for comments
-  gstmts(g, n.sons[0], c)
+  gstmts(g, n[0], c)
   gsons(g, n, c, 1)
 
 proc gfor(g: var TSrcGen, n: PNode) =
   var c: TContext
-  var length = len(n)
   putWithSpace(g, tkFor, "for")
   initContext(c)
   if longMode(g, n) or
-      (lsub(g, n.sons[length - 1]) + lsub(g, n.sons[length - 2]) + 6 + g.lineLen >
-      MaxLineLen):
+      (lsub(g, n[^1]) + lsub(g, n[^2]) + 6 + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcomma(g, n, c, 0, - 3)
   put(g, tkSpaces, Space)
   putWithSpace(g, tkIn, "in")
-  gsub(g, n.sons[length - 2], c)
+  gsub(g, n[^2], c)
   putWithSpace(g, tkColon, ":")
   gcoms(g)
-  gstmts(g, n.sons[length - 1], c)
+  gstmts(g, n[^1], c)
 
 proc gcase(g: var TSrcGen, n: PNode) =
   var c: TContext
   initContext(c)
-  var length = len(n)
-  if length == 0: return
-  var last = if n.sons[length-1].kind == nkElse: -2 else: -1
+  if n.len == 0: return
+  var last = if n[^1].kind == nkElse: -2 else: -1
   if longMode(g, n, 0, last): incl(c.flags, rfLongMode)
   putWithSpace(g, tkCase, "case")
-  gcond(g, n.sons[0])
+  gcond(g, n[0])
   gcoms(g)
   optNL(g)
   gsons(g, n, c, 1, last)
   if last == - 2:
     initContext(c)
-    if longMode(g, n.sons[length - 1]): incl(c.flags, rfLongMode)
-    gsub(g, n.sons[length - 1], c)
+    if longMode(g, n[^1]): incl(c.flags, rfLongMode)
+    gsub(g, n[^1], c)
 
 proc genSymSuffix(result: var string, s: PSym) {.inline.} =
   if sfGenSym in s.flags:
@@ -754,36 +746,36 @@ proc genSymSuffix(result: var string, s: PSym) {.inline.} =
 
 proc gproc(g: var TSrcGen, n: PNode) =
   var c: TContext
-  if n.sons[namePos].kind == nkSym:
-    let s = n.sons[namePos].sym
+  if n[namePos].kind == nkSym:
+    let s = n[namePos].sym
     var ret = renderDefinitionName(s)
     ret.genSymSuffix(s)
     put(g, tkSymbol, ret)
   else:
-    gsub(g, n.sons[namePos])
+    gsub(g, n[namePos])
 
-  if n.sons[patternPos].kind != nkEmpty:
-    gpattern(g, n.sons[patternPos])
+  if n[patternPos].kind != nkEmpty:
+    gpattern(g, n[patternPos])
   let oldInGenericParams = g.inGenericParams
   g.inGenericParams = true
   if renderNoBody in g.flags and n[miscPos].kind != nkEmpty and
       n[miscPos][1].kind != nkEmpty:
     gsub(g, n[miscPos][1])
   else:
-    gsub(g, n.sons[genericParamsPos])
+    gsub(g, n[genericParamsPos])
   g.inGenericParams = oldInGenericParams
-  gsub(g, n.sons[paramsPos])
+  gsub(g, n[paramsPos])
   if renderNoPragmas notin g.flags:
-    gsub(g, n.sons[pragmasPos])
+    gsub(g, n[pragmasPos])
   if renderNoBody notin g.flags:
-    if n.sons[bodyPos].kind != nkEmpty:
+    if n[bodyPos].kind != nkEmpty:
       put(g, tkSpaces, Space)
       putWithSpace(g, tkEquals, "=")
       indentNL(g)
       gcoms(g)
       dedent(g)
       initContext(c)
-      gstmts(g, n.sons[bodyPos], c)
+      gstmts(g, n[bodyPos], c)
       putNL(g)
     else:
       indentNL(g)
@@ -806,33 +798,33 @@ proc gTypeClassTy(g: var TSrcGen, n: PNode) =
 proc gblock(g: var TSrcGen, n: PNode) =
   var c: TContext
   initContext(c)
-  if n.sons[0].kind != nkEmpty:
+  if n[0].kind != nkEmpty:
     putWithSpace(g, tkBlock, "block")
-    gsub(g, n.sons[0])
+    gsub(g, n[0])
   else:
     put(g, tkBlock, "block")
   putWithSpace(g, tkColon, ":")
-  if longMode(g, n) or (lsub(g, n.sons[1]) + g.lineLen > MaxLineLen):
+  if longMode(g, n) or (lsub(g, n[1]) + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcoms(g)
-  gstmts(g, n.sons[1], c)
+  gstmts(g, n[1], c)
 
 proc gstaticStmt(g: var TSrcGen, n: PNode) =
   var c: TContext
   putWithSpace(g, tkStatic, "static")
   putWithSpace(g, tkColon, ":")
   initContext(c)
-  if longMode(g, n) or (lsub(g, n.sons[0]) + g.lineLen > MaxLineLen):
+  if longMode(g, n) or (lsub(g, n[0]) + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcoms(g)                    # a good place for comments
-  gstmts(g, n.sons[0], c)
+  gstmts(g, n[0], c)
 
 proc gasm(g: var TSrcGen, n: PNode) =
   putWithSpace(g, tkAsm, "asm")
-  gsub(g, n.sons[0])
+  gsub(g, n[0])
   gcoms(g)
-  if n.sons.len > 1:
-    gsub(g, n.sons[1])
+  if n.len > 1:
+    gsub(g, n[1])
 
 proc gident(g: var TSrcGen, n: PNode) =
   if g.inGenericParams and n.kind == nkSym:
@@ -866,9 +858,9 @@ proc doParamsAux(g: var TSrcGen, params: PNode) =
     gsemicolon(g, params, 1)
     put(g, tkParRi, ")")
 
-  if params.len > 0 and params.sons[0].kind != nkEmpty:
+  if params.len > 0 and params[0].kind != nkEmpty:
     putWithSpace(g, tkOpr, "->")
-    gsub(g, params.sons[0])
+    gsub(g, params[0])
 
 proc gsub(g: var TSrcGen; n: PNode; i: int) =
   if i < n.len:
@@ -970,19 +962,19 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       put(g, tkColon, ":")
       gsub(g, n, n.len-1)
     else:
-      if len(n) >= 1: accentedName(g, n[0])
+      if n.len >= 1: accentedName(g, n[0])
       put(g, tkParLe, "(")
       gcomma(g, n, 1)
       put(g, tkParRi, ")")
   of nkCallStrLit:
     if n.len > 0: accentedName(g, n[0])
-    if n.len > 1 and n.sons[1].kind == nkRStrLit:
+    if n.len > 1 and n[1].kind == nkRStrLit:
       put(g, tkRStrLit, '\"' & replace(n[1].strVal, "\"", "\"\"") & '\"')
     else:
       gsub(g, n, 1)
   of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv:
     if n.len >= 2:
-      gsub(g, n.sons[1])
+      gsub(g, n[1])
     else:
       put(g, tkSymbol, "(wrong conv)")
   of nkCast:
@@ -997,7 +989,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkAddr, "addr")
     if n.len > 0:
       put(g, tkParLe, "(")
-      gsub(g, n.sons[0])
+      gsub(g, n[0])
       put(g, tkParRi, ")")
   of nkStaticExpr:
     put(g, tkStatic, "static")
@@ -1050,23 +1042,23 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     gcomma(g, n)
     put(g, tkParRi, ")")
   of nkObjDownConv, nkObjUpConv:
-    if len(n) >= 1: gsub(g, n.sons[0])
+    if n.len >= 1: gsub(g, n[0])
     put(g, tkParLe, "(")
     gcomma(g, n, 1)
     put(g, tkParRi, ")")
   of nkClosedSymChoice, nkOpenSymChoice:
     if renderIds in g.flags:
       put(g, tkParLe, "(")
-      for i in 0 ..< len(n):
+      for i in 0..<n.len:
         if i > 0: put(g, tkOpr, "|")
-        if n.sons[i].kind == nkSym:
+        if n[i].kind == nkSym:
           let s = n[i].sym
           if s.owner != nil:
             put g, tkSymbol, n[i].sym.owner.name.s
             put g, tkOpr, "."
           put g, tkSymbol, n[i].sym.name.s
         else:
-          gsub(g, n.sons[i], c)
+          gsub(g, n[i], c)
       put(g, tkParRi, if n.kind == nkOpenSymChoice: "|...)" else: ")")
     else:
       gsub(g, n, 0)
@@ -1113,20 +1105,19 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
   of nkDo:
     putWithSpace(g, tkDo, "do")
     if paramsPos < n.len:
-      doParamsAux(g, n.sons[paramsPos])
+      doParamsAux(g, n[paramsPos])
     gsub(g, n, pragmasPos)
     put(g, tkColon, ":")
     gsub(g, n, bodyPos)
   of nkConstDef, nkIdentDefs:
     gcomma(g, n, 0, -3)
-    var L = len(n)
-    if L >= 2 and n.sons[L - 2].kind != nkEmpty:
+    if n.len >= 2 and n[^2].kind != nkEmpty:
       putWithSpace(g, tkColon, ":")
-      gsub(g, n, L - 2)
-    if L >= 1 and n.sons[L - 1].kind != nkEmpty:
+      gsub(g, n, n.len - 2)
+    if n.len >= 1 and n[^1].kind != nkEmpty:
       put(g, tkSpaces, Space)
       putWithSpace(g, tkEquals, "=")
-      gsub(g, n.sons[L - 1], c)
+      gsub(g, n[^1], c)
   of nkVarTuple:
     put(g, tkParLe, "(")
     gcomma(g, n, 0, -3)
@@ -1142,7 +1133,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     infixArgument(g, n, 1)
     put(g, tkSpaces, Space)
     gsub(g, n, 0)        # binary operator
-    if n.len == 3 and not fits(g, lsub(g, n.sons[2]) + lsub(g, n.sons[0]) + 1):
+    if n.len == 3 and not fits(g, lsub(g, n[2]) + lsub(g, n[0]) + 1):
       optNL(g, g.indent + longIndentWid)
     else:
       put(g, tkSpaces, Space)
@@ -1162,10 +1153,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
         put(g, tkSpaces, Space)
       if nNext.kind == nkInfix:
         put(g, tkParLe, "(")
-        gsub(g, n.sons[1])
+        gsub(g, n[1])
         put(g, tkParRi, ")")
       else:
-        gsub(g, n.sons[1])
+        gsub(g, n[1])
   of nkPostfix:
     gsub(g, n, 1)
     gsub(g, n, 0)
@@ -1178,16 +1169,16 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkOpr, "[]")
   of nkAccQuoted:
     put(g, tkAccent, "`")
-    if n.len > 0: gsub(g, n.sons[0])
-    for i in 1 ..< n.len:
+    if n.len > 0: gsub(g, n[0])
+    for i in 1..<n.len:
       put(g, tkSpaces, Space)
-      gsub(g, n.sons[i])
+      gsub(g, n[i])
     put(g, tkAccent, "`")
   of nkIfExpr:
     putWithSpace(g, tkIf, "if")
-    if n.len > 0: gcond(g, n.sons[0].sons[0])
+    if n.len > 0: gcond(g, n[0][0])
     putWithSpace(g, tkColon, ":")
-    if n.len > 0: gsub(g, n.sons[0], 1)
+    if n.len > 0: gsub(g, n[0], 1)
     gsons(g, n, emptyContext, 1)
   of nkElifExpr:
     putWithSpace(g, tkElif, " elif")
@@ -1201,30 +1192,30 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
   of nkTypeOfExpr:
     put(g, tkType, "typeof")
     put(g, tkParLe, "(")
-    if n.len > 0: gsub(g, n.sons[0])
+    if n.len > 0: gsub(g, n[0])
     put(g, tkParRi, ")")
   of nkRefTy:
-    if len(n) > 0:
+    if n.len > 0:
       putWithSpace(g, tkRef, "ref")
-      gsub(g, n.sons[0])
+      gsub(g, n[0])
     else:
       put(g, tkRef, "ref")
   of nkPtrTy:
-    if len(n) > 0:
+    if n.len > 0:
       putWithSpace(g, tkPtr, "ptr")
-      gsub(g, n.sons[0])
+      gsub(g, n[0])
     else:
       put(g, tkPtr, "ptr")
   of nkVarTy:
-    if len(n) > 0:
+    if n.len > 0:
       putWithSpace(g, tkVar, "var")
-      gsub(g, n.sons[0])
+      gsub(g, n[0])
     else:
       put(g, tkVar, "var")
   of nkDistinctTy:
     if n.len > 0:
       putWithSpace(g, tkDistinct, "distinct")
-      gsub(g, n.sons[0])
+      gsub(g, n[0])
       if n.len > 1:
         if n[1].kind == nkWith:
           putWithSpace(g, tkSymbol, " with")
@@ -1234,32 +1225,32 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     else:
       put(g, tkDistinct, "distinct")
   of nkTypeDef:
-    if n.sons[0].kind == nkPragmaExpr:
+    if n[0].kind == nkPragmaExpr:
       # generate pragma after generic
-      gsub(g, n.sons[0], 0)
+      gsub(g, n[0], 0)
       gsub(g, n, 1)
-      gsub(g, n.sons[0], 1)
+      gsub(g, n[0], 1)
     else:
       gsub(g, n, 0)
       gsub(g, n, 1)
     put(g, tkSpaces, Space)
-    if n.len > 2 and n.sons[2].kind != nkEmpty:
+    if n.len > 2 and n[2].kind != nkEmpty:
       putWithSpace(g, tkEquals, "=")
-      gsub(g, n.sons[2])
+      gsub(g, n[2])
   of nkObjectTy:
-    if len(n) > 0:
+    if n.len > 0:
       putWithSpace(g, tkObject, "object")
-      gsub(g, n.sons[0])
-      gsub(g, n.sons[1])
+      gsub(g, n[0])
+      gsub(g, n[1])
       gcoms(g)
-      gsub(g, n.sons[2])
+      gsub(g, n[2])
     else:
       put(g, tkObject, "object")
   of nkRecList:
     indentNL(g)
-    for i in 0 ..< len(n):
+    for i in 0..<n.len:
       optNL(g)
-      gsub(g, n.sons[i], c)
+      gsub(g, n[i], c)
       gcoms(g)
     dedent(g)
     putNL(g)
@@ -1267,14 +1258,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     putWithSpace(g, tkOf, "of")
     gsub(g, n, 0)
   of nkProcTy:
-    if len(n) > 0:
+    if n.len > 0:
       putWithSpace(g, tkProc, "proc")
       gsub(g, n, 0)
       gsub(g, n, 1)
     else:
       put(g, tkProc, "proc")
   of nkIteratorTy:
-    if len(n) > 0:
+    if n.len > 0:
       putWithSpace(g, tkIterator, "iterator")
       gsub(g, n, 0)
       gsub(g, n, 1)
@@ -1284,12 +1275,12 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkStatic, "static")
     put(g, tkBracketLe, "[")
     if n.len > 0:
-      gsub(g, n.sons[0])
+      gsub(g, n[0])
     put(g, tkBracketRi, "]")
   of nkEnumTy:
-    if len(n) > 0:
+    if n.len > 0:
       putWithSpace(g, tkEnum, "enum")
-      gsub(g, n.sons[0])
+      gsub(g, n[0])
       gcoms(g)
       indentNL(g)
       gcommaAux(g, n, g.indent, 1)
@@ -1345,21 +1336,20 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     incl(a.flags, rfInConstExpr)
     gsection(g, n, a, tkConst, "const")
   of nkVarSection, nkLetSection, nkUsingStmt:
-    var L = len(n)
-    if L == 0: return
+    if n.len == 0: return
     if n.kind == nkVarSection: putWithSpace(g, tkVar, "var")
     elif n.kind == nkLetSection: putWithSpace(g, tkLet, "let")
     else: putWithSpace(g, tkUsing, "using")
-    if L > 1:
+    if n.len > 1:
       gcoms(g)
       indentNL(g)
-      for i in 0 ..< L:
+      for i in 0..<n.len:
         optNL(g)
-        gsub(g, n.sons[i])
+        gsub(g, n[i])
         gcoms(g)
       dedent(g)
     else:
-      gsub(g, n.sons[0])
+      gsub(g, n[0])
   of nkReturnStmt:
     putWithSpace(g, tkReturn, "return")
     if n.len > 0 and n[0].kind == nkAsgn:
@@ -1454,13 +1444,13 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     gsub(g, n, 0)
     putWithSpace(g, tkColon, ":")
     gcoms(g)
-    gstmts(g, n.sons[1], c)
+    gstmts(g, n[1], c)
   of nkElse:
     optNL(g)
     put(g, tkElse, "else")
     putWithSpace(g, tkColon, ":")
     gcoms(g)
-    gstmts(g, n.sons[0], c)
+    gstmts(g, n[0], c)
   of nkFinally, nkDefer:
     optNL(g)
     if n.kind == nkFinally:
@@ -1469,7 +1459,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       put(g, tkDefer, "defer")
     putWithSpace(g, tkColon, ":")
     gcoms(g)
-    gstmts(g, n.sons[0], c)
+    gstmts(g, n[0], c)
   of nkExceptBranch:
     optNL(g)
     if n.len != 1:
@@ -1495,9 +1485,9 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkParLe, "(")
     gsemicolon(g, n, 1)
     put(g, tkParRi, ")")
-    if n.len > 0 and n.sons[0].kind != nkEmpty:
+    if n.len > 0 and n[0].kind != nkEmpty:
       putWithSpace(g, tkColon, ":")
-      gsub(g, n.sons[0])
+      gsub(g, n[0])
   of nkTupleTy:
     put(g, tkTuple, "tuple")
     put(g, tkBracketLe, "[")
@@ -1558,10 +1548,10 @@ proc renderModule*(n: PNode, infile, outfile: string,
     g: TSrcGen
   initSrcGen(g, renderFlags, conf)
   g.fid = fid
-  for i in 0 ..< len(n):
-    gsub(g, n.sons[i])
+  for i in 0..<n.len:
+    gsub(g, n[i])
     optNL(g)
-    case n.sons[i].kind
+    case n[i].kind
     of nkTypeSection, nkConstSection, nkVarSection, nkLetSection,
        nkCommentStmt: putNL(g)
     else: discard
@@ -1577,9 +1567,9 @@ proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) =
   gsub(r, n)
 
 proc getNextTok*(r: var TSrcGen, kind: var TTokType, literal: var string) =
-  if r.idx < len(r.tokens):
+  if r.idx < r.tokens.len:
     kind = r.tokens[r.idx].kind
-    var length = r.tokens[r.idx].length.int
+    let length = r.tokens[r.idx].length.int
     literal = substr(r.buf, r.pos, r.pos + length - 1)
     inc(r.pos, length)
     inc(r.idx)
@@ -1587,7 +1577,7 @@ proc getNextTok*(r: var TSrcGen, kind: var TTokType, literal: var string) =
     kind = tkEof
 
 proc getTokSym*(r: TSrcGen): PSym =
-  if r.idx > 0 and r.idx <= len(r.tokens):
+  if r.idx > 0 and r.idx <= r.tokens.len:
     result = r.tokens[r.idx-1].sym
   else:
     result = nil
diff --git a/compiler/reorder.nim b/compiler/reorder.nim
index 960929811..631806587 100644
--- a/compiler/reorder.nim
+++ b/compiler/reorder.nim
@@ -35,7 +35,7 @@ proc newDepN(id: int, pnode: PNode): DepN =
 
 proc accQuoted(cache: IdentCache; n: PNode): PIdent =
   var id = ""
-  for i in 0 ..< n.len:
+  for i in 0..<n.len:
     let x = n[i]
     case x.kind
     of nkIdent: id.add(x.ident.s)
@@ -75,8 +75,8 @@ proc computeDeps(cache: IdentCache; n: PNode, declares, uses: var IntSet; topLev
   of nkLetSection, nkVarSection, nkUsingStmt:
     for a in n:
       if a.kind in {nkIdentDefs, nkVarTuple}:
-        for j in 0 .. a.len-3: decl(a[j])
-        for j in a.len-2..a.len-1: deps(a[j])
+        for j in 0..<a.len-2: decl(a[j])
+        for j in a.len-2..<a.len: deps(a[j])
   of nkConstSection, nkTypeSection:
     for a in n:
       if a.len >= 3:
@@ -95,19 +95,19 @@ proc computeDeps(cache: IdentCache; n: PNode, declares, uses: var IntSet; topLev
   of nkSym: uses.incl n.sym.name.id
   of nkAccQuoted: uses.incl accQuoted(cache, n).id
   of nkOpenSymChoice, nkClosedSymChoice:
-    uses.incl n.sons[0].sym.name.id
+    uses.incl n[0].sym.name.id
   of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse, nkStaticStmt:
-    for i in 0..<len(n): computeDeps(cache, n[i], declares, uses, topLevel)
+    for i in 0..<n.len: computeDeps(cache, n[i], declares, uses, topLevel)
   of nkPragma:
-    let a = n.sons[0]
-    if a.kind == nkExprColonExpr and a.sons[0].kind == nkIdent and
-       a.sons[0].ident.s == "pragma":
+    let a = n[0]
+    if a.kind == nkExprColonExpr and a[0].kind == nkIdent and
+       a[0].ident.s == "pragma":
         # user defined pragma
-        decl(a.sons[1])
+        decl(a[1])
     else:
-      for i in 0..<safeLen(n): deps(n[i])
+      for i in 0..<n.safeLen: deps(n[i])
   else:
-    for i in 0..<safeLen(n): deps(n[i])
+    for i in 0..<n.safeLen: deps(n[i])
 
 proc cleanPath(s: string): string =
   # Here paths may have the form A / B or "A/B"
@@ -136,7 +136,7 @@ proc hasIncludes(n:PNode): bool =
     if a.kind == nkIncludeStmt:
       return true
 
-proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode {.procvar.} =
+proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode =
   result = syntaxes.parseFile(fileIdx, graph.cache, graph.config)
   graph.addDep(s, fileIdx)
   graph.addIncludeDep(FileIndex s.position, fileIdx)
@@ -150,7 +150,7 @@ proc expandIncludes(graph: ModuleGraph, module: PSym, n: PNode,
   for a in n:
     if a.kind == nkIncludeStmt:
       for i in 0..<a.len:
-        var f = checkModuleName(graph.config, a.sons[i])
+        var f = checkModuleName(graph.config, a[i])
         if f != InvalidFileIdx:
           if containsOrIncl(includedFiles, f.int):
             localError(graph.config, a.info, "recursive dependency: '$1'" %
@@ -206,7 +206,7 @@ proc mergeSections(conf: ConfigRef; comps: seq[seq[DepN]], res: PNode) =
         # need to merge them
         var sn = newNode(kind)
         for dn in cs:
-          sn.add dn.pnode.sons[0]
+          sn.add dn.pnode[0]
         res.add sn
       else:
           # Problematic circular dependency, we arrange the nodes into
@@ -340,7 +340,7 @@ proc buildGraph(n: PNode, deps: seq[(IntSet, IntSet)]): DepG =
   # Build a dependency graph
   result = newSeqOfCap[DepN](deps.len)
   for i in 0..<deps.len:
-    result.add newDepN(i, n.sons[i])
+    result.add newDepN(i, n[i])
   for i in 0..<deps.len:
     var ni = result[i]
     let uses = deps[i][1]
diff --git a/compiler/rodimpl.nim b/compiler/rodimpl.nim
index 188a32dc4..50941535e 100644
--- a/compiler/rodimpl.nim
+++ b/compiler/rodimpl.nim
@@ -156,31 +156,31 @@ proc encodeNode(g: ModuleGraph; fInfo: TLineInfo, n: PNode,
     encodeVInt(n.sym.id, result)
     pushSym(w, n.sym)
   else:
-    for i in 0 ..< len(n):
-      encodeNode(g, n.info, n.sons[i], result)
-  add(result, ')')
+    for i in 0..<n.len:
+      encodeNode(g, n.info, n[i], result)
+  result.add(')')
 
 proc encodeLoc(g: ModuleGraph; loc: TLoc, result: var string) =
   var oldLen = result.len
   result.add('<')
   if loc.k != low(loc.k): encodeVInt(ord(loc.k), result)
   if loc.storage != low(loc.storage):
-    add(result, '*')
+    result.add('*')
     encodeVInt(ord(loc.storage), result)
   if loc.flags != {}:
-    add(result, '$')
+    result.add('$')
     encodeVInt(cast[int32](loc.flags), result)
   if loc.lode != nil:
-    add(result, '^')
+    result.add('^')
     encodeNode(g, unknownLineInfo(), loc.lode, result)
   if loc.r != nil:
-    add(result, '!')
+    result.add('!')
     encodeStr($loc.r, result)
   if oldLen + 1 == result.len:
     # no data was necessary, so remove the '<' again:
     setLen(result, oldLen)
   else:
-    add(result, '>')
+    result.add('>')
 
 proc encodeType(g: ModuleGraph, t: PType, result: var string) =
   if t == nil:
@@ -191,73 +191,73 @@ proc encodeType(g: ModuleGraph, t: PType, result: var string) =
   if t.kind == tyForward: internalError(g.config, "encodeType: tyForward")
   # for the new rodfile viewer we use a preceding [ so that the data section
   # can easily be disambiguated:
-  add(result, '[')
+  result.add('[')
   encodeVInt(ord(t.kind), result)
-  add(result, '+')
+  result.add('+')
   encodeVInt(t.uniqueId, result)
   if t.id != t.uniqueId:
-    add(result, '+')
+    result.add('+')
     encodeVInt(t.id, result)
   if t.n != nil:
     encodeNode(g, unknownLineInfo(), t.n, result)
   if t.flags != {}:
-    add(result, '$')
+    result.add('$')
     encodeVInt(cast[int32](t.flags), result)
   if t.callConv != low(t.callConv):
-    add(result, '?')
+    result.add('?')
     encodeVInt(ord(t.callConv), result)
   if t.owner != nil:
-    add(result, '*')
+    result.add('*')
     encodeVInt(t.owner.id, result)
     pushSym(w, t.owner)
   if t.sym != nil:
-    add(result, '&')
+    result.add('&')
     encodeVInt(t.sym.id, result)
     pushSym(w, t.sym)
   if t.size != - 1:
-    add(result, '/')
+    result.add('/')
     encodeVBiggestInt(t.size, result)
   if t.align != 2:
-    add(result, '=')
+    result.add('=')
     encodeVInt(t.align, result)
   if t.lockLevel.ord != UnspecifiedLockLevel.ord:
-    add(result, '\14')
+    result.add('\14')
     encodeVInt(t.lockLevel.int16, result)
   if t.paddingAtEnd != 0:
-    add(result, '\15')
+    result.add('\15')
     encodeVInt(t.paddingAtEnd, result)
   for a in t.attachedOps:
-    add(result, '\16')
+    result.add('\16')
     if a == nil:
       encodeVInt(-1, result)
     else:
       encodeVInt(a.id, result)
       pushSym(w, a)
   for i, s in items(t.methods):
-    add(result, '\19')
+    result.add('\19')
     encodeVInt(i, result)
-    add(result, '\20')
+    result.add('\20')
     encodeVInt(s.id, result)
     pushSym(w, s)
   encodeLoc(g, t.loc, result)
   if t.typeInst != nil:
-    add(result, '\21')
+    result.add('\21')
     encodeVInt(t.typeInst.uniqueId, result)
     pushType(w, t.typeInst)
-  for i in 0 ..< len(t):
-    if t.sons[i] == nil:
-      add(result, "^()")
+  for i in 0..<t.len:
+    if t[i] == nil:
+      result.add("^()")
     else:
-      add(result, '^')
-      encodeVInt(t.sons[i].uniqueId, result)
-      pushType(w, t.sons[i])
+      result.add('^')
+      encodeVInt(t[i].uniqueId, result)
+      pushType(w, t[i])
 
 proc encodeLib(g: ModuleGraph, lib: PLib, info: TLineInfo, result: var string) =
-  add(result, '|')
+  result.add('|')
   encodeVInt(ord(lib.kind), result)
-  add(result, '|')
+  result.add('|')
   encodeStr($lib.name, result)
-  add(result, '|')
+  result.add('|')
   encodeNode(g, info, lib.path, result)
 
 proc encodeInstantiations(g: ModuleGraph; s: seq[PInstantiation];
@@ -316,7 +316,7 @@ proc encodeSym(g: ModuleGraph, s: PSym, result: var string) =
   encodeLoc(g, s.loc, result)
   if s.annex != nil: encodeLib(g, s.annex, s.info, result)
   if s.constraint != nil:
-    add(result, '#')
+    result.add('#')
     encodeNode(g, unknownLineInfo(), s.constraint, result)
   case s.kind
   of skType, skGenericParam:
diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim
index 17c4832bf..35870a572 100644
--- a/compiler/rodutils.nim
+++ b/compiler/rodutils.nim
@@ -51,10 +51,10 @@ proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string =
     setLen(result, n)
 
 proc encodeStr*(s: string, result: var string) =
-  for i in 0 ..< len(s):
+  for i in 0..<s.len:
     case s[i]
-    of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(result, s[i])
-    else: add(result, '\\' & toHex(ord(s[i]), 2))
+    of 'a'..'z', 'A'..'Z', '0'..'9', '_': result.add(s[i])
+    else: result.add('\\' & toHex(ord(s[i]), 2))
 
 proc hexChar(c: char, xi: var int) =
   case c
@@ -73,9 +73,9 @@ proc decodeStr*(s: cstring, pos: var int): string =
       var xi = 0
       hexChar(s[i-2], xi)
       hexChar(s[i-1], xi)
-      add(result, chr(xi))
+      result.add(chr(xi))
     of 'a'..'z', 'A'..'Z', '0'..'9', '_':
-      add(result, s[i])
+      result.add(s[i])
       inc(i)
     else: break
   pos = i
@@ -96,7 +96,7 @@ template encodeIntImpl(self) =
   var v = x
   var rem = v mod 190
   if rem < 0:
-    add(result, '-')
+    result.add('-')
     v = - (v div 190)
     rem = - rem
   else:
@@ -105,7 +105,7 @@ template encodeIntImpl(self) =
   if idx < 62: d = chars[idx]
   else: d = chr(idx - 62 + 128)
   if v != 0: self(v, result)
-  add(result, d)
+  result.add(d)
 
 proc encodeVBiggestIntAux(x: BiggestInt, result: var string) =
   ## encode a biggest int as a variable length base 190 int.
diff --git a/compiler/ropes.nim b/compiler/ropes.nim
index 774c266b2..1e7957337 100644
--- a/compiler/ropes.nim
+++ b/compiler/ropes.nim
@@ -79,7 +79,7 @@ proc len*(a: Rope): int =
 
 proc newRope(data: string = ""): Rope =
   new(result)
-  result.L = -len(data)
+  result.L = -data.len
   result.data = data
 
 when not compileOption("threads"):
@@ -157,7 +157,7 @@ proc `&`*(a: string, b: Rope): Rope =
 
 proc `&`*(a: openArray[Rope]): Rope =
   ## the concatenation operator for an openarray of ropes.
-  for i in 0 .. high(a): result = result & a[i]
+  for i in 0..high(a): result = result & a[i]
 
 proc add*(a: var Rope, b: Rope) =
   ## adds `b` to the rope `a`.
@@ -202,30 +202,29 @@ proc `$`*(r: Rope): string =
   ## converts a rope back to a string.
   result = newString(r.len)
   setLen(result, 0)
-  for s in leaves(r): add(result, s)
+  for s in leaves(r): result.add(s)
 
 proc ropeConcat*(a: varargs[Rope]): Rope =
   # not overloaded version of concat to speed-up `rfmt` a little bit
-  for i in 0 .. high(a): result = result & a[i]
+  for i in 0..high(a): result = result & a[i]
 
 proc prepend*(a: var Rope, b: Rope) = a = b & a
 proc prepend*(a: var Rope, b: string) = a = b & a
 
 proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope =
   var i = 0
-  var length = len(frmt)
   result = nil
   var num = 0
-  while i < length:
+  while i < frmt.len:
     if frmt[i] == '$':
       inc(i)                  # skip '$'
       case frmt[i]
       of '$':
-        add(result, "$")
+        result.add("$")
         inc(i)
       of '#':
         inc(i)
-        add(result, args[num])
+        result.add(args[num])
         inc(num)
       of '0'..'9':
         var j = 0
@@ -237,7 +236,7 @@ proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope =
         if j > high(args) + 1:
           doAssert false, "invalid format string: " & frmt
         else:
-          add(result, args[j-1])
+          result.add(args[j-1])
       of '{':
         inc(i)
         var j = 0
@@ -252,21 +251,21 @@ proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope =
         if j > high(args) + 1:
           doAssert false, "invalid format string: " & frmt
         else:
-          add(result, args[j-1])
+          result.add(args[j-1])
       of 'n':
-        add(result, "\n")
+        result.add("\n")
         inc(i)
       of 'N':
-        add(result, "\n")
+        result.add("\n")
         inc(i)
       else:
         doAssert false, "invalid format string: " & frmt
     var start = i
-    while i < length:
+    while i < frmt.len:
       if frmt[i] != '$': inc(i)
       else: break
     if i - 1 >= start:
-      add(result, substr(frmt, start, i - 1))
+      result.add(substr(frmt, start, i - 1))
   assert(ropeInvariant(result))
 
 proc `%`*(frmt: static[FormatStr], args: openArray[Rope]): Rope =
@@ -274,7 +273,7 @@ proc `%`*(frmt: static[FormatStr], args: openArray[Rope]): Rope =
 
 template addf*(c: var Rope, frmt: FormatStr, args: openArray[Rope]) =
   ## shortcut for ``add(c, frmt % args)``.
-  add(c, frmt % args)
+  c.add(frmt % args)
 
 when true:
   template `~`*(r: string): Rope = r % []
@@ -301,9 +300,8 @@ proc equalsFile*(r: Rope, f: File): bool =
 
   for s in leaves(r):
     var spos = 0
-    let slen = s.len
-    rtotal += slen
-    while spos < slen:
+    rtotal += s.len
+    while spos < s.len:
       if bpos == blen:
         # Read more data
         bpos = 0
@@ -312,7 +310,7 @@ proc equalsFile*(r: Rope, f: File): bool =
         if blen == 0:  # no more data in file
           result = false
           return
-      let n = min(blen - bpos, slen - spos)
+      let n = min(blen - bpos, s.len - spos)
       # TODO There's gotta be a better way of comparing here...
       if not equalMem(addr(buf[bpos]), cast[pointer](cast[int](cstring(s))+spos), n):
         result = false
diff --git a/compiler/saturate.nim b/compiler/saturate.nim
index 065cb5128..9e8919514 100644
--- a/compiler/saturate.nim
+++ b/compiler/saturate.nim
@@ -36,7 +36,7 @@ proc `|abs|`*(a: BiggestInt): BiggestInt =
     result = low(a)
 
 proc `|div|`*(a, b: BiggestInt): BiggestInt =
-  # (0..5) div (0..4) == (0..5) div (1..4) == (0 div 4) .. (5 div 1)
+  # (0..5) div (0..4) == (0..5) div (1..4) == (0 div 4)..(5 div 1)
   if b == 0'i64:
     # make the same as ``div 1``:
     result = a
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 87f2444a3..7b88de0dc 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -28,9 +28,8 @@ when not defined(leanCompiler):
 
 # implementation
 
-proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.procvar.}
-proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.
-  procvar.}
+proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
+proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
 proc semExprNoType(c: PContext, n: PNode): PNode
 proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
 proc semProcBody(c: PContext, n: PNode): PNode
@@ -128,17 +127,17 @@ proc commonType*(x, y: PType): PType =
       a.kind == b.kind:
     # check for seq[empty] vs. seq[int]
     let idx = ord(b.kind == tyArray)
-    if a.sons[idx].kind == tyEmpty: return y
+    if a[idx].kind == tyEmpty: return y
   elif a.kind == tyTuple and b.kind == tyTuple and a.len == b.len:
     var nt: PType
     for i in 0..<a.len:
-      let aEmpty = isEmptyContainer(a.sons[i])
-      let bEmpty = isEmptyContainer(b.sons[i])
+      let aEmpty = isEmptyContainer(a[i])
+      let bEmpty = isEmptyContainer(b[i])
       if aEmpty != bEmpty:
         if nt.isNil: nt = copyType(a, a.owner, false)
-        nt.sons[i] = if aEmpty: b.sons[i] else: a.sons[i]
+        nt[i] = if aEmpty: b[i] else: a[i]
     if not nt.isNil: result = nt
-    #elif b.sons[idx].kind == tyEmpty: return x
+    #elif b[idx].kind == tyEmpty: return x
   elif a.kind == tyRange and b.kind == tyRange:
     # consider:  (range[0..3], range[0..4]) here. We should make that
     # range[0..4]. But then why is (range[0..4], 6) not range[0..6]?
@@ -278,7 +277,7 @@ when false:
 
 proc hasCycle(n: PNode): bool =
   incl n.flags, nfNone
-  for i in 0..<safeLen(n):
+  for i in 0..<n.safeLen:
     if nfNone in n[i].flags or hasCycle(n[i]):
       result = true
       break
@@ -382,7 +381,7 @@ when false:
   # hopefully not required:
   proc resetSemFlag(n: PNode) =
     excl n.flags, nfSem
-    for i in 0 ..< n.safeLen:
+    for i in 0..<n.safeLen:
       resetSemFlag(n[i])
 
 proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
@@ -400,10 +399,10 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
   result = macroResult
   excl(result.flags, nfSem)
   #resetSemFlag n
-  if s.typ.sons[0] == nil:
+  if s.typ[0] == nil:
     result = semStmt(c, result, flags)
   else:
-    var retType = s.typ.sons[0]
+    var retType = s.typ[0]
     if retType.kind == tyTypeDesc and tfUnresolved in retType.flags and
         retType.len == 1:
       # bug #11941: template fails(T: type X, v: auto): T
@@ -441,7 +440,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
 
       result = semExpr(c, result, flags)
       result = fitNode(c, retType, result, result.info)
-      #globalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
+      #globalError(s.info, errInvalidParamKindX, typeToString(s.typ[0]))
   dec(c.config.evalTemplateCounter)
   discard c.friendModules.pop()
 
@@ -496,13 +495,13 @@ proc semConceptBody(c: PContext, n: PNode): PNode
 include semtypes, semtempl, semgnrc, semstmts, semexprs
 
 proc addCodeForGenerics(c: PContext, n: PNode) =
-  for i in c.lastGenericIdx ..< c.generics.len:
+  for i in c.lastGenericIdx..<c.generics.len:
     var prc = c.generics[i].inst.sym
     if prc.kind in {skProc, skFunc, skMethod, skConverter} and prc.magic == mNone:
-      if prc.ast == nil or prc.ast.sons[bodyPos] == nil:
+      if prc.ast == nil or prc.ast[bodyPos] == nil:
         internalError(c.config, prc.info, "no code for " & prc.name.s)
       else:
-        addSon(n, prc.ast)
+        n.add prc.ast
   c.lastGenericIdx = c.generics.len
 
 proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
@@ -575,9 +574,9 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
     if c.lastGenericIdx < c.generics.len:
       var a = newNodeI(nkStmtList, n.info)
       addCodeForGenerics(c, a)
-      if len(a) > 0:
+      if a.len > 0:
         # a generic has been added to `a`:
-        if result.kind != nkEmpty: addSon(a, result)
+        if result.kind != nkEmpty: a.add result
         result = a
   result = hloStmt(c, result)
   if c.config.cmd == cmdInteractive and not isEmptyType(result.typ):
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 504a9e0c1..13b357023 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -156,11 +156,11 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
   for err in errors:
     var errProto = ""
     let n = err.sym.typ.n
-    for i in 1 ..< n.len:
-      var p = n.sons[i]
+    for i in 1..<n.len:
+      var p = n[i]
       if p.kind == nkSym:
-        add(errProto, typeToString(p.sym.typ, preferName))
-        if i != n.len-1: add(errProto, ", ")
+        errProto.add(typeToString(p.sym.typ, preferName))
+        if i != n.len-1: errProto.add(", ")
       # else: ignore internal error as we're already in error handling mode
     if errProto == proto:
       prefer = preferModuleInfo
@@ -185,11 +185,11 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
       inc skipped
       continue
     if err.sym.kind in routineKinds and err.sym.ast != nil:
-      add(candidates, renderTree(err.sym.ast,
+      candidates.add(renderTree(err.sym.ast,
             {renderNoBody, renderNoComments, renderNoPragmas}))
     else:
-      add(candidates, getProcHeader(c.config, err.sym, prefer))
-    add(candidates, "\n")
+      candidates.add(getProcHeader(c.config, err.sym, prefer))
+    candidates.add("\n")
     let nArg = if err.firstMismatch.arg < n.len: n[err.firstMismatch.arg] else: nil
     let nameParam = if err.firstMismatch.formal != nil: err.firstMismatch.formal.name.s else: ""
     if n.len > 1:
@@ -255,10 +255,10 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
 
   let (prefer, candidates) = presentFailedCandidates(c, n, errors)
   var result = errTypeMismatch
-  add(result, describeArgs(c, n, 1, prefer))
-  add(result, '>')
+  result.add(describeArgs(c, n, 1, prefer))
+  result.add('>')
   if candidates != "":
-    add(result, "\n" & errButExpected & "\n" & candidates)
+    result.add("\n" & errButExpected & "\n" & candidates)
   localError(c.config, n.info, result & "\nexpression: " & $n)
 
 proc bracketNotFoundError(c: PContext; n: PNode) =
@@ -297,14 +297,14 @@ proc getMsgDiagnostic(c: PContext, flags: TExprFlags, n, f: PNode): string =
 
   let ident = considerQuotedIdent(c, f, n).s
   if nfDotField in n.flags and nfExplicitCall notin n.flags:
-    let sym = n.sons[1].typ.sym
+    let sym = n[1].typ.sym
     var typeHint = ""
     if sym == nil:
       # Perhaps we're in a `compiles(foo.bar)` expression, or
       # in a concept, eg:
       #   ExplainedConcept {.explain.} = concept x
       #     x.foo is int
-      # We could use: `(c.config $ n.sons[1].info)` to get more context.
+      # We could use: `(c.config $ n[1].info)` to get more context.
       discard
     else:
       typeHint = " for type " & getProcHeader(c.config, sym)
@@ -319,12 +319,12 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
                       errorsEnabled: bool): TCandidate =
   var initialBinding: PNode
   var alt: TCandidate
-  var f = n.sons[0]
+  var f = n[0]
   if f.kind == nkBracketExpr:
     # fill in the bindings:
     semOpAux(c, f)
     initialBinding = f
-    f = f.sons[0]
+    f = f[0]
   else:
     initialBinding = nil
 
@@ -362,8 +362,8 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
 
       template tryOp(x) =
         let op = newIdentNode(getIdent(c.cache, x), n.info)
-        n.sons[0] = op
-        orig.sons[0] = op
+        n[0] = op
+        orig[0] = op
         pickBest(op)
 
       if nfExplicitCall in n.flags:
@@ -374,7 +374,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
 
     elif nfDotSetter in n.flags and f.kind == nkIdent and n.len == 3:
       # we need to strip away the trailing '=' here:
-      let calleeName = newIdentNode(getIdent(c.cache, f.ident.s[0..f.ident.s.len-2]), n.info)
+      let calleeName = newIdentNode(getIdent(c.cache, f.ident.s[0..^2]), n.info)
       let callOp = newIdentNode(getIdent(c.cache, ".="), n.info)
       n.sons[0..1] = [callOp, n[1], calleeName]
       orig.sons[0..1] = [callOp, orig[1], calleeName]
@@ -392,7 +392,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
         if {nfDotField, nfDotSetter} * n.flags != {}:
           # clean up the inserted ops
           n.sons.delete(2)
-          n.sons[0] = f
+          n[0] = f
       return
   if alt.state == csMatch and cmpCandidates(result, alt) == 0 and
       not sameMethodDispatcher(result.calleeSym, alt.calleeSym):
@@ -405,10 +405,10 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
     elif c.config.errorCounter == 0:
       # don't cascade errors
       var args = "("
-      for i in 1 ..< len(n):
-        if i > 1: add(args, ", ")
-        add(args, typeToString(n.sons[i].typ))
-      add(args, ")")
+      for i in 1..<n.len:
+        if i > 1: args.add(", ")
+        args.add(typeToString(n[i].typ))
+      args.add(")")
 
       localError(c.config, n.info, errAmbiguousCallXYZ % [
         getProcHeader(c.config, result.calleeSym),
@@ -417,31 +417,29 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
 
 proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) =
   let a = if a.kind == nkHiddenDeref: a[0] else: a
-  if a.kind == nkHiddenCallConv and a.sons[0].kind == nkSym:
-    let s = a.sons[0].sym
+  if a.kind == nkHiddenCallConv and a[0].kind == nkSym:
+    let s = a[0].sym
     if s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty:
       let finalCallee = generateInstance(c, s, x.bindings, a.info)
-      a.sons[0].sym = finalCallee
-      a.sons[0].typ = finalCallee.typ
-      #a.typ = finalCallee.typ.sons[0]
+      a[0].sym = finalCallee
+      a[0].typ = finalCallee.typ
+      #a.typ = finalCallee.typ[0]
 
 proc instGenericConvertersSons*(c: PContext, n: PNode, x: TCandidate) =
   assert n.kind in nkCallKinds
   if x.genericConverter:
-    for i in 1 ..< n.len:
-      instGenericConvertersArg(c, n.sons[i], x)
+    for i in 1..<n.len:
+      instGenericConvertersArg(c, n[i], x)
 
 proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode =
-  var m: TCandidate
-  initCandidate(c, m, f)
+  var m = newCandidate(c, f)
   result = paramTypesMatch(m, f, a, arg, nil)
   if m.genericConverter and result != nil:
     instGenericConvertersArg(c, result, m)
 
 proc inferWithMetatype(c: PContext, formal: PType,
                        arg: PNode, coerceDistincts = false): PNode =
-  var m: TCandidate
-  initCandidate(c, m, formal)
+  var m = newCandidate(c, formal)
   m.coerceDistincts = coerceDistincts
   result = paramTypesMatch(m, formal, arg.typ, arg, nil)
   if m.genericConverter and result != nil:
@@ -475,8 +473,8 @@ proc updateDefaultParams(call: PNode) =
 proc getCallLineInfo(n: PNode): TLineInfo =
   case n.kind
   of nkAccQuoted, nkBracketExpr, nkCall, nkCallStrLit, nkCommand:
-    getCallLineInfo(n.sons[0])
-  of nkDotExpr: getCallLineInfo(n.sons[1])
+    getCallLineInfo(n[0])
+  of nkDotExpr: getCallLineInfo(n[1])
   else: n.info
 
 proc semResolvedCall(c: PContext, x: TCandidate,
@@ -489,12 +487,12 @@ proc semResolvedCall(c: PContext, x: TCandidate,
   assert finalCallee.ast != nil
   if x.hasFauxMatch:
     result = x.call
-    result.sons[0] = newSymNode(finalCallee, getCallLineInfo(result.sons[0]))
+    result[0] = newSymNode(finalCallee, getCallLineInfo(result[0]))
     if containsGenericType(result.typ) or x.fauxMatch == tyUnknown:
       result.typ = newTypeS(x.fauxMatch, c)
       if result.typ.kind == tyError: incl result.typ.flags, tfCheckedForDestructor
     return
-  let gp = finalCallee.ast.sons[genericParamsPos]
+  let gp = finalCallee.ast[genericParamsPos]
   if gp.kind != nkEmpty:
     if x.calleeSym.kind notin {skMacro, skTemplate}:
       if x.calleeSym.magic in {mArrGet, mArrPut}:
@@ -516,7 +514,7 @@ proc semResolvedCall(c: PContext, x: TCandidate,
   result = x.call
   instGenericConvertersSons(c, result, x)
   result[0] = newSymNode(finalCallee, getCallLineInfo(result[0]))
-  result.typ = finalCallee.typ.sons[0]
+  result.typ = finalCallee.typ[0]
   updateDefaultParams(result)
 
 proc canDeref(n: PNode): bool {.inline.} =
@@ -525,8 +523,8 @@ proc canDeref(n: PNode): bool {.inline.} =
 
 proc tryDeref(n: PNode): PNode =
   result = newNodeI(nkHiddenDeref, n.info)
-  result.typ = n.typ.skipTypes(abstractInst).sons[0]
-  result.addSon(n)
+  result.typ = n.typ.skipTypes(abstractInst)[0]
+  result.add n
 
 proc semOverloadedCall(c: PContext, n, nOrig: PNode,
                        filter: TSymKinds, flags: TExprFlags): PNode =
@@ -548,12 +546,12 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
     # inside `resolveOverloads` or it could be moved all the way
     # into sigmatch with hidden conversion produced there
     #
-    n.sons[1] = n.sons[1].tryDeref
+    n[1] = n[1].tryDeref
     var r = resolveOverloads(c, n, nOrig, filter, flags, errors, efExplain in flags)
     if r.state == csMatch: result = semResolvedCall(c, r, n, flags)
     else:
       # get rid of the deref again for a better error message:
-      n.sons[1] = n.sons[1].sons[0]
+      n[1] = n[1][0]
       #notFoundError(c, n, errors)
       if efExplain notin flags:
         # repeat the overload resolution,
@@ -574,12 +572,11 @@ proc explicitGenericInstError(c: PContext; n: PNode): PNode =
   result = n
 
 proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
-  var m: TCandidate
   # binding has to stay 'nil' for this to work!
-  initCandidate(c, m, s, nil)
+  var m = newCandidate(c, s, nil)
 
-  for i in 1..len(n)-1:
-    let formal = s.ast.sons[genericParamsPos].sons[i-1].typ
+  for i in 1..<n.len:
+    let formal = s.ast[genericParamsPos][i-1].typ
     var arg = n[i].typ
     # try transforming the argument into a static one before feeding it into
     # typeRel
@@ -600,19 +597,19 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
 
 proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
   assert n.kind == nkBracketExpr
-  for i in 1..len(n)-1:
-    let e = semExpr(c, n.sons[i])
+  for i in 1..<n.len:
+    let e = semExpr(c, n[i])
     if e.typ == nil:
-      n.sons[i].typ = errorType(c)
+      n[i].typ = errorType(c)
     else:
-      n.sons[i].typ = e.typ.skipTypes({tyTypeDesc})
+      n[i].typ = e.typ.skipTypes({tyTypeDesc})
   var s = s
-  var a = n.sons[0]
+  var a = n[0]
   if a.kind == nkSym:
     # common case; check the only candidate has the right
     # number of generic type parameters:
-    if safeLen(s.ast.sons[genericParamsPos]) != n.len-1:
-      let expected = safeLen(s.ast.sons[genericParamsPos])
+    if s.ast[genericParamsPos].safeLen != n.len-1:
+      let expected = s.ast[genericParamsPos].safeLen
       localError(c.config, getCallLineInfo(n), errGenerated, "cannot instantiate: '" & renderTree(n) &
          "'; got " & $(n.len-1) & " type(s) but expected " & $expected)
       return n
@@ -623,13 +620,13 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
     # XXX I think this could be improved by reusing sigmatch.paramTypesMatch.
     # It's good enough for now.
     result = newNodeI(a.kind, getCallLineInfo(n))
-    for i in 0 ..< len(a):
-      var candidate = a.sons[i].sym
+    for i in 0..<a.len:
+      var candidate = a[i].sym
       if candidate.kind in {skProc, skMethod, skConverter,
                             skFunc, skIterator}:
         # it suffices that the candidate has the proper number of generic
         # type parameters:
-        if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
+        if candidate.ast[genericParamsPos].safeLen == n.len-1:
           let x = explicitGenericSym(c, n, candidate)
           if x != nil: result.add(x)
     # get rid of nkClosedSymChoice if not ambiguous:
@@ -649,7 +646,7 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
   var hasDistinct = false
   call.add(newIdentNode(fn.name, fn.info))
   for i in 1..<fn.typ.n.len:
-    let param = fn.typ.n.sons[i]
+    let param = fn.typ.n[i]
     let t = skipTypes(param.typ, abstractVar-{tyTypeDesc, tyDistinct})
     if t.kind == tyDistinct or param.typ.kind == tyDistinct: hasDistinct = true
     var x: PType
@@ -662,8 +659,8 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
   if hasDistinct:
     var resolved = semOverloadedCall(c, call, call, {fn.kind}, {})
     if resolved != nil:
-      result = resolved.sons[0].sym
-      if not compareTypes(result.typ.sons[0], fn.typ.sons[0], dcEqIgnoreDistinct):
+      result = resolved[0].sym
+      if not compareTypes(result.typ[0], fn.typ[0], dcEqIgnoreDistinct):
         result = nil
       elif result.magic in {mArrPut, mArrGet}:
         # cannot borrow these magics for now
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 7caabe13c..367c0eaf6 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -162,11 +162,10 @@ proc getCurrOwner*(c: PContext): PSym =
   result = c.graph.owners[^1]
 
 proc pushOwner*(c: PContext; owner: PSym) =
-  add(c.graph.owners, owner)
+  c.graph.owners.add(owner)
 
 proc popOwner*(c: PContext) =
-  var length = len(c.graph.owners)
-  if length > 0: setLen(c.graph.owners, length - 1)
+  if c.graph.owners.len > 0: setLen(c.graph.owners, c.graph.owners.len - 1)
   else: internalError(c.config, "popOwner")
 
 proc lastOptionEntry*(c: PContext): POptionEntry =
@@ -203,7 +202,7 @@ proc considerGenSyms*(c: PContext; n: PNode) =
       n.sym = s
   else:
     for i in 0..<n.safeLen:
-      considerGenSyms(c, n.sons[i])
+      considerGenSyms(c, n[i])
 
 proc newOptionEntry*(conf: ConfigRef): POptionEntry =
   new(result)
@@ -250,11 +249,9 @@ proc newContext*(graph: ModuleGraph; module: PSym): PContext =
   result.features = graph.config.features
 
 proc inclSym(sq: var seq[PSym], s: PSym) =
-  var L = len(sq)
-  for i in 0 ..< L:
+  for i in 0..<sq.len:
     if sq[i].id == s.id: return
-  setLen(sq, L + 1)
-  sq[L] = s
+  sq.add s
 
 proc addConverter*(c: PContext, conv: PSym) =
   inclSym(c.converters, conv)
@@ -407,8 +404,8 @@ proc makeRangeType*(c: PContext; first, last: BiggestInt;
                     info: TLineInfo; intType: PType = nil): PType =
   let intType = if intType != nil: intType else: getSysType(c.graph, info, tyInt)
   var n = newNodeI(nkRange, info)
-  addSon(n, newIntTypeNode(first, intType))
-  addSon(n, newIntTypeNode(last, intType))
+  n.add newIntTypeNode(first, intType)
+  n.add newIntTypeNode(last, intType)
   result = newTypeS(tyRange, c)
   result.n = n
   addSonSkipIntLit(result, intType) # basetype of range
@@ -425,16 +422,16 @@ proc illFormedAstLocal*(n: PNode; conf: ConfigRef) =
   localError(conf, n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
 
 proc checkSonsLen*(n: PNode, length: int; conf: ConfigRef) =
-  if len(n) != length: illFormedAst(n, conf)
+  if n.len != length: illFormedAst(n, conf)
 
 proc checkMinSonsLen*(n: PNode, length: int; conf: ConfigRef) =
-  if len(n) < length: illFormedAst(n, conf)
+  if n.len < length: illFormedAst(n, conf)
 
 proc isTopLevel*(c: PContext): bool {.inline.} =
   result = c.currentScope.depthLevel <= 2
 
 proc pushCaseContext*(c: PContext, caseNode: PNode) =
-  add(c.p.caseContext, (caseNode, 0))
+  c.p.caseContext.add((caseNode, 0))
 
 proc popCaseContext*(c: PContext) =
   discard pop(c.p.caseContext)
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 2e9c5e1f5..c87ab21b1 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -225,13 +225,13 @@ proc isOwnedSym(c: PContext; n: PNode): bool =
   result = s != nil and sfSystemModule in s.owner.flags and s.name.s == "owned"
 
 proc semConv(c: PContext, n: PNode): PNode =
-  if len(n) != 2:
+  if n.len != 2:
     localError(c.config, n.info, "a type conversion takes exactly one argument")
     return n
 
   result = newNodeI(nkConv, n.info)
 
-  var targetType = semTypeNode(c, n.sons[0], nil)
+  var targetType = semTypeNode(c, n[0], nil)
   if targetType.kind == tyTypeDesc:
     internalAssert c.config, targetType.len > 0
     if targetType.base.kind == tyNone:
@@ -252,7 +252,7 @@ proc semConv(c: PContext, n: PNode): PNode =
   maybeLiftType(targetType, c, n[0].info)
 
   if targetType.kind in {tySink, tyLent} or isOwnedSym(c, n[0]):
-    let baseType = semTypeNode(c, n.sons[1], nil).skipTypes({tyTypeDesc})
+    let baseType = semTypeNode(c, n[1], nil).skipTypes({tyTypeDesc})
     let t = newTypeS(targetType.kind, c)
     if targetType.kind == tyOwned:
       t.flags.incl tfHasOwned
@@ -261,23 +261,23 @@ proc semConv(c: PContext, n: PNode): PNode =
     result.typ = makeTypeDesc(c, t)
     return
 
-  result.addSon copyTree(n.sons[0])
+  result.add copyTree(n[0])
 
   # special case to make MyObject(x = 3) produce a nicer error message:
   if n[1].kind == nkExprEqExpr and
       targetType.skipTypes(abstractPtrs).kind == tyObject:
     localError(c.config, n.info, "object construction uses ':', not '='")
-  var op = semExprWithType(c, n.sons[1])
+  var op = semExprWithType(c, n[1])
   if targetType.isMetaType:
     let final = inferWithMetatype(c, targetType, op, true)
-    result.addSon final
+    result.add final
     result.typ = final.typ
     return
 
   result.typ = targetType
   # XXX op is overwritten later on, this is likely added too early
   # here or needs to be overwritten too then.
-  addSon(result, op)
+  result.add op
 
   if not isSymChoice(op):
     let status = checkConvertible(c, result.typ, op)
@@ -285,13 +285,13 @@ proc semConv(c: PContext, n: PNode): PNode =
     of convOK:
       # handle SomeProcType(SomeGenericProc)
       if op.kind == nkSym and op.sym.isGenericRoutine:
-        result.sons[1] = fitNode(c, result.typ, result.sons[1], result.info)
+        result[1] = fitNode(c, result.typ, result[1], result.info)
       elif op.kind in {nkPar, nkTupleConstr} and targetType.kind == tyTuple:
         op = fitNode(c, targetType, op, result.info)
     of convNotNeedeed:
       message(c.config, n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString)
     of convNotLegal:
-      result = fitNode(c, result.typ, result.sons[1], result.info)
+      result = fitNode(c, result.typ, result[1], result.info)
       if result == nil:
         localError(c.config, n.info, "illegal conversion from '$1' to '$2'" %
           [op.typ.typeToString, result.typ.typeToString])
@@ -301,23 +301,23 @@ proc semConv(c: PContext, n: PNode): PNode =
       localError(c.config, n.info, errGenerated, value & " can't be converted to " &
         result.typ.typeToString)
   else:
-    for i in 0 ..< len(op):
-      let it = op.sons[i]
+    for i in 0..<op.len:
+      let it = op[i]
       let status = checkConvertible(c, result.typ, it)
       if status in {convOK, convNotNeedeed}:
         markUsed(c, n.info, it.sym)
         onUse(n.info, it.sym)
         markIndirect(c, it.sym)
         return it
-    errorUseQualifier(c, n.info, op.sons[0].sym)
+    errorUseQualifier(c, n.info, op[0].sym)
 
 proc semCast(c: PContext, n: PNode): PNode =
   ## Semantically analyze a casting ("cast[type](param)")
   checkSonsLen(n, 2, c.config)
-  let targetType = semTypeNode(c, n.sons[0], nil)
-  let castedExpr = semExprWithType(c, n.sons[1])
+  let targetType = semTypeNode(c, n[0], nil)
+  let castedExpr = semExprWithType(c, n[1])
   if tfHasMeta in targetType.flags:
-    localError(c.config, n.sons[0].info, "cannot cast to a non concrete type: '$1'" % $targetType)
+    localError(c.config, n[0].info, "cannot cast to a non concrete type: '$1'" % $targetType)
   if not isCastable(c.config, targetType, castedExpr.typ):
     let tar = $targetType
     let alt = typeToString(targetType, preferDesc)
@@ -325,24 +325,24 @@ proc semCast(c: PContext, n: PNode): PNode =
     localError(c.config, n.info, "expression cannot be cast to " & msg)
   result = newNodeI(nkCast, n.info)
   result.typ = targetType
-  addSon(result, copyTree(n.sons[0]))
-  addSon(result, castedExpr)
+  result.add copyTree(n[0])
+  result.add castedExpr
 
 proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
   const
     opToStr: array[mLow..mHigh, string] = ["low", "high"]
-  if len(n) != 2:
+  if n.len != 2:
     localError(c.config, n.info, errXExpectsTypeOrValue % opToStr[m])
   else:
-    n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
-    var typ = skipTypes(n.sons[1].typ, abstractVarRange + {tyTypeDesc, tyUserTypeClassInst})
+    n[1] = semExprWithType(c, n[1], {efDetermineType})
+    var typ = skipTypes(n[1].typ, abstractVarRange + {tyTypeDesc, tyUserTypeClassInst})
     case typ.kind
     of tySequence, tyString, tyCString, tyOpenArray, tyVarargs:
       n.typ = getSysType(c.graph, n.info, tyInt)
     of tyArray:
-      n.typ = typ.sons[0] # indextype
+      n.typ = typ[0] # indextype
     of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt..tyUInt64, tyFloat..tyFloat64:
-      n.typ = n.sons[1].typ.skipTypes({tyTypeDesc})
+      n.typ = n[1].typ.skipTypes({tyTypeDesc})
     of tyGenericParam:
       # prepare this for resolving in semtypinst:
       # we must use copyTree here in order to avoid creating a cycle
@@ -397,8 +397,7 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
       res = false
   else:
     maybeLiftType(t2, c, n.info)
-    var m: TCandidate
-    initCandidate(c, m, t2)
+    var m = newCandidate(c, t2)
     if efExplain in flags:
       m.diagnostics = @[]
       m.diagnosticsEnabled = true
@@ -408,7 +407,7 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
   result.typ = n.typ
 
 proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
-  if len(n) != 3:
+  if n.len != 3:
     localError(c.config, n.info, "'is' operator takes 2 arguments")
 
   let boolType = getSysType(c.graph, n.info, tyBool)
@@ -416,10 +415,10 @@ proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
   n.typ = boolType
   var liftLhs = true
 
-  n.sons[1] = semExprWithType(c, n[1], {efDetermineType, efWantIterator})
+  n[1] = semExprWithType(c, n[1], {efDetermineType, efWantIterator})
   if n[2].kind notin {nkStrLit..nkTripleStrLit}:
     let t2 = semTypeNode(c, n[2], nil)
-    n.sons[2] = newNodeIT(nkType, n[2].info, t2)
+    n[2] = newNodeIT(nkType, n[2].info, t2)
     if t2.kind == tyStatic:
       let evaluated = tryConstExpr(c, n[1])
       if evaluated != nil:
@@ -435,7 +434,7 @@ proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
       # not allow regular values to be matched against the type:
       liftLhs = false
   else:
-    n.sons[2] = semExpr(c, n[2])
+    n[2] = semExpr(c, n[2])
 
   var lhsType = n[1].typ
   if lhsType.kind != tyTypeDesc:
@@ -452,15 +451,15 @@ proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
 
 proc semOpAux(c: PContext, n: PNode) =
   const flags = {efDetermineType}
-  for i in 1 ..< n.len:
-    var a = n.sons[i]
-    if a.kind == nkExprEqExpr and len(a) == 2:
-      let info = a.sons[0].info
-      a.sons[0] = newIdentNode(considerQuotedIdent(c, a.sons[0], a), info)
-      a.sons[1] = semExprWithType(c, a.sons[1], flags)
-      a.typ = a.sons[1].typ
+  for i in 1..<n.len:
+    var a = n[i]
+    if a.kind == nkExprEqExpr and a.len == 2:
+      let info = a[0].info
+      a[0] = newIdentNode(considerQuotedIdent(c, a[0], a), info)
+      a[1] = semExprWithType(c, a[1], flags)
+      a.typ = a[1].typ
     else:
-      n.sons[i] = semExprWithType(c, a, flags)
+      n[i] = semExprWithType(c, a, flags)
 
 proc overloadedCallOpr(c: PContext, n: PNode): PNode =
   # quick check if there is *any* () operator overloaded:
@@ -469,24 +468,24 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode =
     result = nil
   else:
     result = newNodeI(nkCall, n.info)
-    addSon(result, newIdentNode(par, n.info))
-    for i in 0 ..< len(n): addSon(result, n.sons[i])
+    result.add newIdentNode(par, n.info)
+    for i in 0..<n.len: result.add n[i]
     result = semExpr(c, result)
 
 proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
   case n.kind
   of nkCurly, nkBracket:
-    for i in 0 ..< len(n):
-      changeType(c, n.sons[i], elemType(newType), check)
+    for i in 0..<n.len:
+      changeType(c, n[i], elemType(newType), check)
   of nkPar, nkTupleConstr:
     let tup = newType.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct})
     if tup.kind != tyTuple:
       if tup.kind == tyObject: return
       globalError(c.config, n.info, "no tuple type for constructor")
-    elif len(n) > 0 and n.sons[0].kind == nkExprColonExpr:
+    elif n.len > 0 and n[0].kind == nkExprColonExpr:
       # named tuple?
-      for i in 0 ..< len(n):
-        var m = n.sons[i].sons[0]
+      for i in 0..<n.len:
+        var m = n[i][0]
         if m.kind != nkSym:
           globalError(c.config, m.info, "invalid tuple constructor")
           return
@@ -495,18 +494,18 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
           if f == nil:
             globalError(c.config, m.info, "unknown identifier: " & m.sym.name.s)
             return
-          changeType(c, n.sons[i].sons[1], f.typ, check)
+          changeType(c, n[i][1], f.typ, check)
         else:
-          changeType(c, n.sons[i].sons[1], tup.sons[i], check)
+          changeType(c, n[i][1], tup[i], check)
     else:
-      for i in 0 ..< len(n):
-        changeType(c, n.sons[i], tup.sons[i], check)
+      for i in 0..<n.len:
+        changeType(c, n[i], tup[i], check)
         when false:
-          var m = n.sons[i]
-          var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
-          addSon(a, newSymNode(newType.n.sons[i].sym))
-          addSon(a, m)
-          changeType(m, tup.sons[i], check)
+          var m = n[i]
+          var a = newNodeIT(nkExprColonExpr, m.info, newType[i])
+          a.add newSymNode(newType.n[i].sym)
+          a.add m
+          changeType(m, tup[i], check)
   of nkCharLit..nkUInt64Lit:
     if check and n.kind != nkUInt64Lit:
       let value = n.intVal
@@ -522,12 +521,12 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
 proc arrayConstrType(c: PContext, n: PNode): PType =
   var typ = newTypeS(tyArray, c)
   rawAddSon(typ, nil)     # index type
-  if len(n) == 0:
+  if n.len == 0:
     rawAddSon(typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
   else:
-    var t = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
+    var t = skipTypes(n[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
     addSonSkipIntLit(typ, t)
-  typ.sons[0] = makeRangeType(c, 0, len(n) - 1, n.info)
+  typ[0] = makeRangeType(c, 0, n.len - 1, n.info)
   result = typ
 
 proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
@@ -538,13 +537,13 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
     firstIndex, lastIndex: Int128
     indexType = getSysType(c.graph, n.info, tyInt)
     lastValidIndex = lastOrd(c.config, indexType)
-  if len(n) == 0:
+  if n.len == 0:
     rawAddSon(result.typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
     lastIndex = toInt128(-1)
   else:
-    var x = n.sons[0]
-    if x.kind == nkExprColonExpr and len(x) == 2:
-      var idx = semConstExpr(c, x.sons[0])
+    var x = n[0]
+    if x.kind == nkExprColonExpr and x.len == 2:
+      var idx = semConstExpr(c, x[0])
       if not isOrdinalType(idx.typ):
         localError(c.config, idx.info, "expected ordinal value for array " &
                    "index, got '$1'" % renderTree(idx))
@@ -553,51 +552,51 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
         lastIndex = firstIndex
         indexType = idx.typ
         lastValidIndex = lastOrd(c.config, indexType)
-        x = x.sons[1]
+        x = x[1]
 
     let yy = semExprWithType(c, x)
     var typ = yy.typ
-    addSon(result, yy)
-    #var typ = skipTypes(result.sons[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal})
-    for i in 1 ..< len(n):
+    result.add yy
+    #var typ = skipTypes(result[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal})
+    for i in 1..<n.len:
       if lastIndex == lastValidIndex:
         let validIndex = makeRangeType(c, toInt64(firstIndex), toInt64(lastValidIndex), n.info,
                                        indexType)
         localError(c.config, n.info, "size of array exceeds range of index " &
           "type '$1' by $2 elements" % [typeToString(validIndex), $(n.len-i)])
 
-      x = n.sons[i]
-      if x.kind == nkExprColonExpr and len(x) == 2:
-        var idx = semConstExpr(c, x.sons[0])
+      x = n[i]
+      if x.kind == nkExprColonExpr and x.len == 2:
+        var idx = semConstExpr(c, x[0])
         idx = fitNode(c, indexType, idx, x.info)
         if lastIndex+1 != getOrdValue(idx):
           localError(c.config, x.info, "invalid order in array constructor")
-        x = x.sons[1]
+        x = x[1]
 
       let xx = semExprWithType(c, x, flags*{efAllowDestructor})
       result.add xx
       typ = commonType(typ, xx.typ)
-      #n.sons[i] = semExprWithType(c, x, flags*{efAllowDestructor})
-      #addSon(result, fitNode(c, typ, n.sons[i]))
+      #n[i] = semExprWithType(c, x, flags*{efAllowDestructor})
+      #result.add fitNode(c, typ, n[i])
       inc(lastIndex)
     addSonSkipIntLit(result.typ, typ)
-    for i in 0 ..< result.len:
-      result.sons[i] = fitNode(c, typ, result.sons[i], result.sons[i].info)
-  result.typ.sons[0] = makeRangeType(c, toInt64(firstIndex), toInt64(lastIndex), n.info,
+    for i in 0..<result.len:
+      result[i] = fitNode(c, typ, result[i], result[i].info)
+  result.typ[0] = makeRangeType(c, toInt64(firstIndex), toInt64(lastIndex), n.info,
                                      indexType)
 
 proc fixAbstractType(c: PContext, n: PNode) =
-  for i in 1 ..< n.len:
-    let it = n.sons[i]
+  for i in 1..<n.len:
+    let it = n[i]
     # do not get rid of nkHiddenSubConv for OpenArrays, the codegen needs it:
     if it.kind == nkHiddenSubConv and
         skipTypes(it.typ, abstractVar).kind notin {tyOpenArray, tyVarargs}:
-      if skipTypes(it.sons[1].typ, abstractVar).kind in
+      if skipTypes(it[1].typ, abstractVar).kind in
             {tyNil, tyTuple, tySet} or it[1].isArrayConstr:
         var s = skipTypes(it.typ, abstractVar)
         if s.kind != tyUntyped:
-          changeType(c, it.sons[1], s, check=true)
-        n.sons[i] = it.sons[1]
+          changeType(c, it[1], s, check=true)
+        n[i] = it[1]
 
 proc isAssignable(c: PContext, n: PNode; isUnsafeAddr=false): TAssignableResult =
   result = parampatterns.isAssignable(c.p.owner, n, isUnsafeAddr)
@@ -629,17 +628,17 @@ proc hasUnresolvedArgs(c: PContext, n: PNode): bool =
       return false
   else:
     for i in 0..<n.safeLen:
-      if hasUnresolvedArgs(c, n.sons[i]): return true
+      if hasUnresolvedArgs(c, n[i]): return true
     return false
 
 proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
   if n.kind == nkHiddenDeref and not (c.config.cmd == cmdCompileToCpp or
                                       sfCompileToCpp in c.module.flags):
     checkSonsLen(n, 1, c.config)
-    result = n.sons[0]
+    result = n[0]
   else:
     result = newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ))
-    addSon(result, n)
+    result.add n
     if isAssignable(c, n) notin {arLValue, arLocalLValue}:
       localError(c.config, n.info, errVarForOutParamNeededX % renderNotLValue(n))
 
@@ -654,16 +653,16 @@ proc analyseIfAddressTaken(c: PContext, n: PNode): PNode =
       result = newHiddenAddrTaken(c, n)
   of nkDotExpr:
     checkSonsLen(n, 2, c.config)
-    if n.sons[1].kind != nkSym:
+    if n[1].kind != nkSym:
       internalError(c.config, n.info, "analyseIfAddressTaken")
       return
-    if skipTypes(n.sons[1].sym.typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}:
-      incl(n.sons[1].sym.flags, sfAddrTaken)
+    if skipTypes(n[1].sym.typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}:
+      incl(n[1].sym.flags, sfAddrTaken)
       result = newHiddenAddrTaken(c, n)
   of nkBracketExpr:
     checkMinSonsLen(n, 1, c.config)
-    if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}:
-      if n.sons[0].kind == nkSym: incl(n.sons[0].sym.flags, sfAddrTaken)
+    if skipTypes(n[0].typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}:
+      if n[0].kind == nkSym: incl(n[0].sym.flags, sfAddrTaken)
       result = newHiddenAddrTaken(c, n)
   else:
     result = newHiddenAddrTaken(c, n)
@@ -678,14 +677,14 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
 
   # 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, tyAlias, tySink})
+  var t = n[0].typ.skipTypes({tyGenericInst, tyAlias, tySink})
 
-  if n.sons[0].kind == nkSym and n.sons[0].sym.magic in FakeVarParams:
+  if n[0].kind == nkSym and n[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 1 ..< len(n):
-      if i < len(t) and t.sons[i] != nil and
-          skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar:
+    for i in 1..<n.len:
+      if i < t.len and t[i] != nil and
+          skipTypes(t[i], abstractInst-{tyTypeDesc}).kind == tyVar:
         let it = n[i]
         if isAssignable(c, it) notin {arLValue, arLocalLValue}:
           if it.kind != nkHiddenAddr:
@@ -699,23 +698,23 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
         localError(c.config, n.info, errXStackEscape % renderTree(n[1], {renderNoComments}))
 
     return
-  for i in 1 ..< len(n):
+  for i in 1..<n.len:
     let n = if n.kind == nkHiddenDeref: n[0] else: n
-    if n.sons[i].kind == nkHiddenCallConv:
+    if n[i].kind == nkHiddenCallConv:
       # we need to recurse explicitly here as converters can create nested
       # calls and then they wouldn't be analysed otherwise
-      analyseIfAddressTakenInCall(c, n.sons[i])
-    if i < len(t) and
-        skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar:
-      if n.sons[i].kind != nkHiddenAddr:
-        n.sons[i] = analyseIfAddressTaken(c, n.sons[i])
+      analyseIfAddressTakenInCall(c, n[i])
+    if i < t.len and
+        skipTypes(t[i], abstractInst-{tyTypeDesc}).kind == tyVar:
+      if n[i].kind != nkHiddenAddr:
+        n[i] = analyseIfAddressTaken(c, n[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
+  if n.kind notin nkCallKinds or n[0].kind != nkSym: return
+  var callee = n[0].sym
   # workaround for bug #537 (overly aggressive inlining leading to
   # wrong NimNode semantics):
   if n.typ != nil and tfTriggersCompileTime in n.typ.flags: return
@@ -723,14 +722,14 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
   # 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)
-    call.add(n.sons[0])
+    call.add(n[0])
     var allConst = true
-    for i in 1 ..< n.len:
-      var a = getConstExpr(c.module, n.sons[i], c.graph)
+    for i in 1..<n.len:
+      var a = getConstExpr(c.module, n[i], c.graph)
       if a == nil:
         allConst = false
-        a = n.sons[i]
-        if a.kind == nkHiddenStdConv: a = a.sons[1]
+        a = n[i]
+        if a.kind == nkHiddenStdConv: a = a[1]
       call.add(a)
     if allConst:
       result = semfold.getConstExpr(c.module, call, c.graph)
@@ -743,7 +742,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
     # done until we have a more robust infrastructure for
     # implicit statics.
     if n.len > 1:
-      for i in 1 ..< n.len:
+      for i in 1..<n.len:
         # see bug #2113, it's possible that n[i].typ for errornous code:
         if n[i].typ.isNil or n[i].typ.kind != tyStatic or
             tfUnresolved notin n[i].typ.flags:
@@ -768,9 +767,9 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
     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:
-      let a = getConstExpr(c.module, n.sons[i], c.graph)
+    call.add(n[0])
+    for i in 1..<n.len:
+      let a = getConstExpr(c.module, n[i], c.graph)
       if a == nil: return n
       call.add(a)
 
@@ -818,10 +817,10 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
       {skProc, skFunc, skMethod, skConverter, skMacro, skTemplate}, flags)
 
   if result != nil:
-    if result.sons[0].kind != nkSym:
+    if result[0].kind != nkSym:
       internalError(c.config, "semOverloadedCallAnalyseEffects")
       return
-    let callee = result.sons[0].sym
+    let callee = result[0].sym
     case callee.kind
     of skMacro, skTemplate: discard
     else:
@@ -829,7 +828,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
         localError(c.config, n.info, errRecursiveDependencyIteratorX % callee.name.s)
         # error correction, prevents endless for loop elimination in transf.
         # See bug #2051:
-        result.sons[0] = newSymNode(errorSym(c, n))
+        result[0] = newSymNode(errorSym(c, n))
 
 proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode
 
@@ -840,7 +839,7 @@ proc resolveIndirectCall(c: PContext; n, nOrig: PNode;
   if result.state != csMatch:
     # try to deref the first argument:
     if implicitDeref in c.features and canDeref(n):
-      n.sons[1] = n.sons[1].tryDeref
+      n[1] = n[1].tryDeref
       initCandidate(c, result, t)
       matches(c, n, nOrig, result)
 
@@ -851,12 +850,12 @@ proc bracketedMacro(n: PNode): PSym =
       result = nil
 
 proc setGenericParams(c: PContext, n: PNode) =
-  for i in 1 ..< n.len:
+  for i in 1..<n.len:
     n[i].typ = semTypeNode(c, n[i], nil)
 
 proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
   result = n
-  let callee = result.sons[0].sym
+  let callee = result[0].sym
   case callee.kind
   of skMacro: result = semMacroExpr(c, result, orig, callee, flags)
   of skTemplate: result = semTemplateExpr(c, result, callee, flags)
@@ -869,7 +868,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
       result = magicsAfterOverloadResolution(c, result, flags)
     when false:
       if result.typ != nil and
-          not (result.typ.kind == tySequence and result.typ.sons[0].kind == tyEmpty):
+          not (result.typ.kind == tySequence and result.typ[0].kind == tyEmpty):
         liftTypeBoundOps(c, result.typ, n.info)
     #result = patchResolvedTypeBoundOp(c, result)
   if c.matchedConcept == nil:
@@ -878,26 +877,26 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
 proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
   result = nil
   checkMinSonsLen(n, 1, c.config)
-  var prc = n.sons[0]
-  if n.sons[0].kind == nkDotExpr:
-    checkSonsLen(n.sons[0], 2, c.config)
-    let n0 = semFieldAccess(c, n.sons[0])
+  var prc = n[0]
+  if n[0].kind == nkDotExpr:
+    checkSonsLen(n[0], 2, c.config)
+    let n0 = semFieldAccess(c, n[0])
     if n0.kind == nkDotCall:
       # it is a static call!
       result = n0
       result.kind = nkCall
       result.flags.incl nfExplicitCall
-      for i in 1 ..< len(n): addSon(result, n.sons[i])
+      for i in 1..<n.len: result.add n[i]
       return semExpr(c, result, flags)
     else:
-      n.sons[0] = n0
+      n[0] = n0
   else:
-    n.sons[0] = semExpr(c, n.sons[0], {efInCall})
-    let t = n.sons[0].typ
+    n[0] = semExpr(c, n[0], {efInCall})
+    let t = n[0].typ
     if t != nil and t.kind in {tyVar, tyLent}:
-      n.sons[0] = newDeref(n.sons[0])
-    elif n.sons[0].kind == nkBracketExpr:
-      let s = bracketedMacro(n.sons[0])
+      n[0] = newDeref(n[0])
+    elif n[0].kind == nkBracketExpr:
+      let s = bracketedMacro(n[0])
       if s != nil:
         setGenericParams(c, n[0])
         return semDirectOp(c, n, flags)
@@ -905,8 +904,8 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
   let nOrig = n.copyTree
   semOpAux(c, n)
   var t: PType = nil
-  if n.sons[0].typ != nil:
-    t = skipTypes(n.sons[0].typ, abstractInst+{tyOwned}-{tyTypeDesc, tyDistinct})
+  if n[0].typ != nil:
+    t = skipTypes(n[0].typ, abstractInst+{tyOwned}-{tyTypeDesc, tyDistinct})
   if t != nil and t.kind == tyProc:
     # This is a proc variable, apply normal overload resolution
     let m = resolveIndirectCall(c, n, nOrig, t)
@@ -918,16 +917,16 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
       else:
         var hasErrorType = false
         var msg = "type mismatch: got <"
-        for i in 1 ..< len(n):
-          if i > 1: add(msg, ", ")
-          let nt = n.sons[i].typ
-          add(msg, typeToString(nt))
+        for i in 1..<n.len:
+          if i > 1: msg.add(", ")
+          let nt = n[i].typ
+          msg.add(typeToString(nt))
           if nt.kind == tyError:
             hasErrorType = true
             break
         if not hasErrorType:
-          add(msg, ">\nbut expected one of: \n" &
-              typeToString(n.sons[0].typ))
+          msg.add(">\nbut expected one of: \n" &
+              typeToString(n[0].typ))
           localError(c.config, n.info, msg)
         return errorNode(c, n)
       result = nil
@@ -945,8 +944,8 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
     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
-      nOrig.sons[0] = prc
+      n[0] = prc
+      nOrig[0] = prc
       n.flags.incl nfExprCall
       result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
       if result == nil: return errorNode(c, n)
@@ -955,7 +954,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
       # See bug #904 of how to trigger it:
       return result
   #result = afterCallActions(c, result, nOrig, flags)
-  if result.sons[0].kind == nkSym:
+  if result[0].kind == nkSym:
     result = afterCallActions(c, result, nOrig, flags)
   else:
     fixAbstractType(c, result)
@@ -974,11 +973,11 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode =
   result = newNodeI(nkCall, n.info)
   var e = strTableGet(c.graph.systemModule.tab, getIdent(c.cache, "echo"))
   if e != nil:
-    add(result, newSymNode(e))
+    result.add(newSymNode(e))
   else:
     localError(c.config, n.info, "system needs: echo")
-    add(result, errorNode(c, n))
-  add(result, n)
+    result.add(errorNode(c, n))
+  result.add(n)
   result = semExpr(c, result)
 
 proc semExprNoType(c: PContext, n: PNode): PNode =
@@ -1006,50 +1005,50 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
   result = nil
   case r.kind
   of nkRecList:
-    for i in 0 ..< len(r):
-      result = lookupInRecordAndBuildCheck(c, n, r.sons[i], field, check)
+    for i in 0..<r.len:
+      result = lookupInRecordAndBuildCheck(c, n, r[i], field, check)
       if result != nil: return
   of nkRecCase:
     checkMinSonsLen(r, 2, c.config)
-    if (r.sons[0].kind != nkSym): illFormedAst(r, c.config)
-    result = lookupInRecordAndBuildCheck(c, n, r.sons[0], field, check)
+    if (r[0].kind != nkSym): illFormedAst(r, c.config)
+    result = lookupInRecordAndBuildCheck(c, n, r[0], field, check)
     if result != nil: return
-    let setType = createSetType(c, r.sons[0].typ)
+    let setType = createSetType(c, r[0].typ)
     var s = newNodeIT(nkCurly, r.info, setType)
-    for i in 1 ..< len(r):
-      var it = r.sons[i]
+    for i in 1..<r.len:
+      var it = r[i]
       case it.kind
       of nkOfBranch:
         result = lookupInRecordAndBuildCheck(c, n, lastSon(it), field, check)
         if result == nil:
-          for j in 0..len(it)-2: addSon(s, copyTree(it.sons[j]))
+          for j in 0..<it.len-1: s.add copyTree(it[j])
         else:
           if check == nil:
             check = newNodeI(nkCheckedFieldExpr, n.info)
-            addSon(check, c.graph.emptyNode) # make space for access node
+            check.add c.graph.emptyNode # make space for access node
           s = newNodeIT(nkCurly, n.info, setType)
-          for j in 0 .. len(it) - 2: addSon(s, copyTree(it.sons[j]))
+          for j in 0..<it.len - 1: s.add copyTree(it[j])
           var inExpr = newNodeIT(nkCall, n.info, getSysType(c.graph, n.info, tyBool))
-          addSon(inExpr, newSymNode(c.graph.opContains, n.info))
-          addSon(inExpr, s)
-          addSon(inExpr, copyTree(r.sons[0]))
-          addSon(check, inExpr)
-          #addSon(check, semExpr(c, inExpr))
+          inExpr.add newSymNode(c.graph.opContains, n.info)
+          inExpr.add s
+          inExpr.add copyTree(r[0])
+          check.add inExpr
+          #check.add semExpr(c, inExpr)
           return
       of nkElse:
         result = lookupInRecordAndBuildCheck(c, n, lastSon(it), field, check)
         if result != nil:
           if check == nil:
             check = newNodeI(nkCheckedFieldExpr, n.info)
-            addSon(check, c.graph.emptyNode) # make space for access node
+            check.add c.graph.emptyNode # make space for access node
           var inExpr = newNodeIT(nkCall, n.info, getSysType(c.graph, n.info, tyBool))
-          addSon(inExpr, newSymNode(c.graph.opContains, n.info))
-          addSon(inExpr, s)
-          addSon(inExpr, copyTree(r.sons[0]))
+          inExpr.add newSymNode(c.graph.opContains, n.info)
+          inExpr.add s
+          inExpr.add copyTree(r[0])
           var notExpr = newNodeIT(nkCall, n.info, getSysType(c.graph, n.info, tyBool))
-          addSon(notExpr, newSymNode(c.graph.opNot, n.info))
-          addSon(notExpr, inExpr)
-          addSon(check, notExpr)
+          notExpr.add newSymNode(c.graph.opNot, n.info)
+          notExpr.add inExpr
+          check.add notExpr
           return
       else: illFormedAst(it, c.config)
   of nkSym:
@@ -1087,13 +1086,13 @@ proc readTypeParameter(c: PContext, typ: PType,
         discard
 
   if typ.kind != tyUserTypeClass:
-    let ty = if typ.kind == tyCompositeTypeClass: typ.sons[1].skipGenericAlias
+    let ty = if typ.kind == tyCompositeTypeClass: typ[1].skipGenericAlias
              else: typ.skipGenericAlias
-    let tbody = ty.sons[0]
-    for s in 0 .. tbody.len-2:
-      let tParam = tbody.sons[s]
+    let tbody = ty[0]
+    for s in 0..<tbody.len-1:
+      let tParam = tbody[s]
       if tParam.sym.name.id == paramName.id:
-        let rawTyp = ty.sons[s + 1]
+        let rawTyp = ty[s + 1]
         if rawTyp.kind == tyStatic:
           if rawTyp.n != nil:
             return rawTyp.n
@@ -1227,12 +1226,12 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
             result.add makeDeref(newSymNode(p.selfSym))
             result.add newSymNode(f) # we now have the correct field
             if check != nil:
-              check.sons[0] = result
+              check[0] = result
               check.typ = result.typ
               result = check
             return result
-          if ty.sons[0] == nil: break
-          ty = skipTypes(ty.sons[0], skipPtrs)
+          if ty[0] == nil: break
+          ty = skipTypes(ty[0], skipPtrs)
     # old code, not sure if it's live code:
     markUsed(c, n.info, s)
     onUse(n.info, s)
@@ -1250,7 +1249,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
   # tests/bind/tbindoverload.nim wants an early exit here, but seems to
   # work without now. template/tsymchoicefield doesn't like an early exit
   # here at all!
-  #if isSymChoice(n.sons[1]): return
+  #if isSymChoice(n[1]): return
   when defined(nimsuggest):
     if c.config.cmd == cmdIdeTools:
       suggestExpr(c, n)
@@ -1262,15 +1261,15 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
       result = symChoice(c, n, s, scClosed)
       if result.kind == nkSym: result = semSym(c, n, s, flags)
     else:
-      markUsed(c, n.sons[1].info, s)
+      markUsed(c, n[1].info, s)
       result = semSym(c, n, s, flags)
-    onUse(n.sons[1].info, s)
+    onUse(n[1].info, s)
     return
 
-  n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType})
-  #restoreOldStyleType(n.sons[0])
-  var i = considerQuotedIdent(c, n.sons[1], n)
-  var ty = n.sons[0].typ
+  n[0] = semExprWithType(c, n[0], flags+{efDetermineType})
+  #restoreOldStyleType(n[0])
+  var i = considerQuotedIdent(c, n[1], n)
+  var ty = n[0].typ
   var f: PSym = nil
   result = nil
 
@@ -1311,7 +1310,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
       ty = ty.base
       argIsType = true
   else:
-    argIsType = isTypeExpr(n.sons[0])
+    argIsType = isTypeExpr(n[0])
 
   if argIsType:
     ty = ty.skipTypes(tyDotOpTransparent)
@@ -1321,7 +1320,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
       while ty != nil:
         f = getSymFromList(ty.n, i)
         if f != nil: break
-        ty = ty.sons[0]         # enum inheritance
+        ty = ty[0]         # enum inheritance
       if f != nil:
         result = newSymNode(f)
         result.info = n.info
@@ -1340,7 +1339,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
       return
     # XXX: This is probably not relevant any more
     # reset to prevent 'nil' bug: see "tests/reject/tenumitems.nim":
-    ty = n.sons[0].typ
+    ty = n[0].typ
     return nil
   if ty.kind in tyUserTypeClasses and ty.isResolvedUserTypeClass:
     ty = ty.lastSon
@@ -1352,8 +1351,8 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
       check = nil
       f = lookupInRecordAndBuildCheck(c, n, ty.n, i, check)
       if f != nil: break
-      if ty.sons[0] == nil: break
-      ty = skipTypes(ty.sons[0], skipPtrs)
+      if ty[0] == nil: break
+      ty = skipTypes(ty[0], skipPtrs)
     if f != nil:
       let visibilityCheckNeeded =
         if n[1].kind == nkSym and n[1].sym == f:
@@ -1361,43 +1360,43 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
         else: true
       if not visibilityCheckNeeded or fieldVisible(c, f):
         # is the access to a public field or in the same module or in a friend?
-        markUsed(c, n.sons[1].info, f)
-        onUse(n.sons[1].info, f)
-        n.sons[0] = makeDeref(n.sons[0])
-        n.sons[1] = newSymNode(f) # we now have the correct field
+        markUsed(c, n[1].info, f)
+        onUse(n[1].info, f)
+        n[0] = makeDeref(n[0])
+        n[1] = newSymNode(f) # we now have the correct field
         n.typ = f.typ
         if check == nil:
           result = n
         else:
-          check.sons[0] = n
+          check[0] = n
           check.typ = n.typ
           result = check
   elif ty.kind == tyTuple and ty.n != nil:
     f = getSymFromList(ty.n, i)
     if f != nil:
-      markUsed(c, n.sons[1].info, f)
-      onUse(n.sons[1].info, f)
-      n.sons[0] = makeDeref(n.sons[0])
-      n.sons[1] = newSymNode(f)
+      markUsed(c, n[1].info, f)
+      onUse(n[1].info, f)
+      n[0] = makeDeref(n[0])
+      n[1] = newSymNode(f)
       n.typ = f.typ
       result = n
 
   # we didn't find any field, let's look for a generic param
   if result == nil:
-    let t = n.sons[0].typ.skipTypes(tyDotOpTransparent)
+    let t = n[0].typ.skipTypes(tyDotOpTransparent)
     tryReadingGenericParam(t)
 
 proc dotTransformation(c: PContext, n: PNode): PNode =
-  if isSymChoice(n.sons[1]):
+  if isSymChoice(n[1]):
     result = newNodeI(nkDotCall, n.info)
-    addSon(result, n.sons[1])
-    addSon(result, copyTree(n[0]))
+    result.add n[1]
+    result.add copyTree(n[0])
   else:
-    var i = considerQuotedIdent(c, n.sons[1], n)
+    var i = considerQuotedIdent(c, n[1], n)
     result = newNodeI(nkDotCall, n.info)
     result.flags.incl nfDotField
-    addSon(result, newIdentNode(i, n[1].info))
-    addSon(result, copyTree(n[0]))
+    result.add newIdentNode(i, n[1].info)
+    result.add copyTree(n[0])
 
 proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
   # this is difficult, because the '.' is used in many different contexts
@@ -1409,22 +1408,22 @@ proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
 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])
+  for s in n: result.add s
 
 proc semDeref(c: PContext, n: PNode): PNode =
   checkSonsLen(n, 1, c.config)
-  n.sons[0] = semExprWithType(c, n.sons[0])
+  n[0] = semExprWithType(c, n[0])
   result = n
-  var t = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyLent, tyAlias, tySink, tyOwned})
+  var t = skipTypes(n[0].typ, {tyGenericInst, tyVar, tyLent, tyAlias, tySink, tyOwned})
   case t.kind
   of tyRef, tyPtr: n.typ = t.lastSon
   else: result = nil
-  #GlobalError(n.sons[0].info, errCircumNeedsPointer)
+  #GlobalError(n[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 len(n) == 1:
+  if n.len == 1:
     let x = semDeref(c, n)
     if x == nil: return nil
     result = newNodeIT(nkDerefExpr, x.info, x.typ)
@@ -1432,9 +1431,9 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
     return
   checkMinSonsLen(n, 2, c.config)
   # make sure we don't evaluate generic macros/templates
-  n.sons[0] = semExprWithType(c, n.sons[0],
+  n[0] = semExprWithType(c, n[0],
                               {efNoEvaluateGeneric})
-  var arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyUserTypeClassInst, tyOwned,
+  var arr = skipTypes(n[0].typ, {tyGenericInst, tyUserTypeClassInst, tyOwned,
                                       tyVar, tyLent, tyPtr, tyRef, tyAlias, tySink})
   if arr.kind == tyStatic:
     if arr.base.kind == tyNone:
@@ -1450,20 +1449,20 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
   of tyArray, tyOpenArray, tyVarargs, tySequence, tyString, tyCString,
     tyUncheckedArray:
     if n.len != 2: return nil
-    n.sons[0] = makeDeref(n.sons[0])
-    for i in 1 ..< len(n):
-      n.sons[i] = semExprWithType(c, n.sons[i],
+    n[0] = makeDeref(n[0])
+    for i in 1..<n.len:
+      n[i] = semExprWithType(c, n[i],
                                   flags*{efInTypeof, efDetermineType})
     # Arrays index type is dictated by the range's type
     if arr.kind == tyArray:
-      var indexType = arr.sons[0]
-      var arg = indexTypesMatch(c, indexType, n.sons[1].typ, n.sons[1])
+      var indexType = arr[0]
+      var arg = indexTypesMatch(c, indexType, n[1].typ, n[1])
       if arg != nil:
-        n.sons[1] = arg
+        n[1] = arg
         result = n
         result.typ = elemType(arr)
     # Other types have a bit more of leeway
-    elif n.sons[1].typ.skipTypes(abstractRange-{tyDistinct}).kind in
+    elif n[1].typ.skipTypes(abstractRange-{tyDistinct}).kind in
         {tyInt..tyInt64, tyUInt..tyUInt64}:
       result = n
       result.typ = elemType(arr)
@@ -1476,31 +1475,31 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
     #result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
   of tyTuple:
     if n.len != 2: return nil
-    n.sons[0] = makeDeref(n.sons[0])
+    n[0] = makeDeref(n[0])
     # [] operator for tuples requires constant expression:
-    n.sons[1] = semConstExpr(c, n.sons[1])
-    if skipTypes(n.sons[1].typ, {tyGenericInst, tyRange, tyOrdinal, tyAlias, tySink}).kind in
+    n[1] = semConstExpr(c, n[1])
+    if skipTypes(n[1].typ, {tyGenericInst, tyRange, tyOrdinal, tyAlias, tySink}).kind in
         {tyInt..tyInt64}:
-      let idx = getOrdValue(n.sons[1])
-      if idx >= 0 and idx < len(arr): n.typ = arr.sons[toInt(idx)]
+      let idx = getOrdValue(n[1])
+      if idx >= 0 and idx < arr.len: n.typ = arr[toInt(idx)]
       else: localError(c.config, n.info, "invalid index value for tuple subscript")
       result = n
     else:
       result = nil
   else:
-    let s = if n.sons[0].kind == nkSym: n.sons[0].sym
-            elif n[0].kind in nkSymChoices: n.sons[0][0].sym
+    let s = if n[0].kind == nkSym: n[0].sym
+            elif n[0].kind in nkSymChoices: n[0][0].sym
             else: nil
     if s != nil:
       case s.kind
       of skProc, skFunc, skMethod, skConverter, skIterator:
         # type parameters: partial generic specialization
-        n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s)
+        n[0] = semSymGenericInstantiation(c, n[0], s)
         result = explicitGenericInstantiation(c, n, s)
         if result == n:
-          n.sons[0] = copyTree(result)
+          n[0] = copyTree(result)
         else:
-          n.sons[0] = result
+          n[0] = result
       of skMacro, skTemplate:
         if efInCall in flags:
           # We are processing macroOrTmpl[] in macroOrTmpl[](...) call.
@@ -1557,9 +1556,9 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode =
         root.name.s, renderTree(n, {renderNoComments}), explanationsBaseUrl])
   case n.kind
   of nkHiddenAddr, nkAddr: return n
-  of nkHiddenDeref, nkDerefExpr: return n.sons[0]
+  of nkHiddenDeref, nkDerefExpr: return n[0]
   of nkBracketExpr:
-    if len(n) == 1: return n.sons[0]
+    if n.len == 1: return n[0]
   else: discard
   let valid = isAssignable(c, n, isLent)
   if valid != arLValue:
@@ -1572,10 +1571,10 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode =
 
 proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
   if le.kind == nkHiddenDeref:
-    var x = le.sons[0]
+    var x = le[0]
     if x.typ.kind in {tyVar, tyLent} and x.kind == nkSym and x.sym.kind == skResult:
-      n.sons[0] = x # 'result[]' --> 'result'
-      n.sons[1] = takeImplicitAddr(c, ri, x.typ.kind == tyLent)
+      n[0] = x # 'result[]' --> 'result'
+      n[1] = takeImplicitAddr(c, ri, x.typ.kind == tyLent)
       x.typ.flags.incl tfVarIsPtr
       #echo x.info, " setting it for this type ", typeToString(x.typ), " ", n.info
 
@@ -1633,7 +1632,7 @@ proc goodLineInfo(arg: PNode): TLineInfo =
 
 proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
   checkSonsLen(n, 2, c.config)
-  var a = n.sons[0]
+  var a = n[0]
   case a.kind
   of nkDotExpr:
     # r.f = x
@@ -1654,8 +1653,8 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
     # --> `[]=`(a, i, x)
     a = semSubscript(c, a, {efLValue})
     if a == nil:
-      result = buildOverloadedSubscripts(n.sons[0], getIdent(c.cache, "[]="))
-      add(result, n[1])
+      result = buildOverloadedSubscripts(n[0], getIdent(c.cache, "[]="))
+      result.add(n[1])
       if mode == noOverloadedSubscript:
         bracketNotFoundError(c, result)
         return n
@@ -1664,8 +1663,8 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
         return result
   of nkCurlyExpr:
     # a{i} = x -->  `{}=`(a, i, x)
-    result = buildOverloadedSubscripts(n.sons[0], getIdent(c.cache, "{}="))
-    add(result, n[1])
+    result = buildOverloadedSubscripts(n[0], getIdent(c.cache, "{}="))
+    result.add(n[1])
     return semExprNoType(c, result)
   of nkPar, nkTupleConstr:
     if a.len >= 2:
@@ -1677,7 +1676,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
       a = semExprWithType(c, a, {efLValue})
   else:
     a = semExprWithType(c, a, {efLValue})
-  n.sons[0] = a
+  n[0] = a
   # a = b # both are vars, means: a[] = b[]
   # a = b # b no 'var T' means: a = addr(b)
   var le = a.typ
@@ -1691,10 +1690,10 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
                renderTree(a, {renderNoComments}))
   else:
     let
-      lhs = n.sons[0]
+      lhs = n[0]
       lhsIsResult = lhs.kind == nkSym and lhs.sym.kind == skResult
     var
-      rhs = semExprWithType(c, n.sons[1],
+      rhs = semExprWithType(c, n[1],
         if lhsIsResult: {efAllowDestructor} else: {})
     if lhsIsResult:
       n.typ = c.enforceVoidContext
@@ -1708,16 +1707,16 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
           typeAllowedCheck(c.config, n.info, rhsTyp, skResult)
           lhs.typ = rhsTyp
           c.p.resultSym.typ = rhsTyp
-          c.p.owner.typ.sons[0] = rhsTyp
+          c.p.owner.typ[0] = rhsTyp
         else:
           typeMismatch(c.config, n.info, lhs.typ, rhsTyp)
     borrowCheck(c, n, lhs, rhs)
 
-    n.sons[1] = fitNode(c, le, rhs, goodLineInfo(n[1]))
+    n[1] = fitNode(c, le, rhs, goodLineInfo(n[1]))
     when false: liftTypeBoundOps(c, lhs.typ, lhs.info)
 
     fixAbstractType(c, n)
-    asgnToResultVar(c, n, n.sons[0], n.sons[1])
+    asgnToResultVar(c, n, n[0], n[1])
   result = n
 
 proc semReturn(c: PContext, n: PNode): PNode =
@@ -1725,16 +1724,16 @@ proc semReturn(c: PContext, n: PNode): PNode =
   checkSonsLen(n, 1, c.config)
   if c.p.owner.kind in {skConverter, skMethod, skProc, skFunc, skMacro} or
       (not c.p.owner.typ.isNil and isClosureIterator(c.p.owner.typ)):
-    if n.sons[0].kind != nkEmpty:
+    if n[0].kind != nkEmpty:
       # transform ``return expr`` to ``result = expr; return``
       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)
+        var a = newNodeI(nkAsgn, n[0].info)
+        a.add newSymNode(c.p.resultSym)
+        a.add n[0]
+        n[0] = semAsgn(c, a)
         # optimize away ``result = result``:
         if n[0][1].kind == nkSym and n[0][1].sym == c.p.resultSym:
-          n.sons[0] = c.graph.emptyNode
+          n[0] = c.graph.emptyNode
       else:
         localError(c.config, n.info, errNoReturnTypeDeclared)
   else:
@@ -1756,8 +1755,8 @@ proc semProcBody(c: PContext, n: PNode): PNode =
       fixNilType(c, result)
     else:
       var a = newNodeI(nkAsgn, n.info, 2)
-      a.sons[0] = newSymNode(c.p.resultSym)
-      a.sons[1] = result
+      a[0] = newSymNode(c.p.resultSym)
+      a[1] = result
       result = semAsgn(c, a)
   else:
     discardCheck(c, result, {})
@@ -1767,12 +1766,12 @@ proc semProcBody(c: PContext, n: PNode): PNode =
     if isEmptyType(result.typ):
       # we inferred a 'void' return type:
       c.p.resultSym.typ = errorType(c)
-      c.p.owner.typ.sons[0] = nil
+      c.p.owner.typ[0] = nil
     else:
       localError(c.config, c.p.resultSym.info, errCannotInferReturnType %
         c.p.owner.name.s)
-  if isInlineIterator(c.p.owner.typ) and c.p.owner.typ.sons[0] != nil and
-      c.p.owner.typ.sons[0].kind == tyUntyped:
+  if isInlineIterator(c.p.owner.typ) and c.p.owner.typ[0] != nil and
+      c.p.owner.typ[0].kind == tyUntyped:
     localError(c.config, c.p.owner.info, errCannotInferReturnType %
       c.p.owner.name.s)
   closeScope(c)
@@ -1782,22 +1781,22 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) =
   case t.kind
   of tyVar, tyLent:
     t.flags.incl tfVarIsPtr # bugfix for #4048, #4910, #6892
-    if n.sons[0].kind in {nkHiddenStdConv, nkHiddenSubConv}:
-      n.sons[0] = n.sons[0].sons[1]
-    n.sons[0] = takeImplicitAddr(c, n.sons[0], t.kind == tyLent)
+    if n[0].kind in {nkHiddenStdConv, nkHiddenSubConv}:
+      n[0] = n[0][1]
+    n[0] = takeImplicitAddr(c, n[0], t.kind == tyLent)
   of tyTuple:
     for i in 0..<t.len:
-      let e = skipTypes(t.sons[i], {tyGenericInst, tyAlias, tySink})
+      let e = skipTypes(t[i], {tyGenericInst, tyAlias, tySink})
       if e.kind in {tyVar, tyLent}:
         e.flags.incl tfVarIsPtr # bugfix for #4048, #4910, #6892
-        if n.sons[0].kind in {nkPar, nkTupleConstr}:
-          n.sons[0].sons[i] = takeImplicitAddr(c, n.sons[0].sons[i], e.kind == tyLent)
-        elif n.sons[0].kind in {nkHiddenStdConv, nkHiddenSubConv} and
-             n.sons[0].sons[1].kind in {nkPar, nkTupleConstr}:
-          var a = n.sons[0].sons[1]
-          a.sons[i] = takeImplicitAddr(c, a.sons[i], e.kind == tyLent)
+        if n[0].kind in {nkPar, nkTupleConstr}:
+          n[0][i] = takeImplicitAddr(c, n[0][i], e.kind == tyLent)
+        elif n[0].kind in {nkHiddenStdConv, nkHiddenSubConv} and
+             n[0][1].kind in {nkPar, nkTupleConstr}:
+          var a = n[0][1]
+          a[i] = takeImplicitAddr(c, a[i], e.kind == tyLent)
         else:
-          localError(c.config, n.sons[0].info, errXExpected, "tuple constructor")
+          localError(c.config, n[0].info, errXExpected, "tuple constructor")
   else: discard
 
 proc semYield(c: PContext, n: PNode): PNode =
@@ -1805,25 +1804,25 @@ proc semYield(c: PContext, n: PNode): PNode =
   checkSonsLen(n, 1, c.config)
   if c.p.owner == nil or c.p.owner.kind != skIterator:
     localError(c.config, n.info, errYieldNotAllowedHere)
-  elif n.sons[0].kind != nkEmpty:
-    n.sons[0] = semExprWithType(c, n.sons[0]) # check for type compatibility:
+  elif n[0].kind != nkEmpty:
+    n[0] = semExprWithType(c, n[0]) # check for type compatibility:
     var iterType = c.p.owner.typ
-    let restype = iterType.sons[0]
+    let restype = iterType[0]
     if restype != nil:
       if restype.kind != tyUntyped:
-        n.sons[0] = fitNode(c, restype, n.sons[0], n.info)
-      if n.sons[0].typ == nil: internalError(c.config, n.info, "semYield")
+        n[0] = fitNode(c, restype, n[0], n.info)
+      if n[0].typ == nil: internalError(c.config, n.info, "semYield")
 
       if resultTypeIsInferrable(restype):
-        let inferred = n.sons[0].typ
-        iterType.sons[0] = inferred
+        let inferred = n[0].typ
+        iterType[0] = inferred
         if c.p.resultSym != nil:
           c.p.resultSym.typ = inferred
 
       semYieldVarResult(c, n, restype)
     else:
       localError(c.config, n.info, errCannotReturnExpr)
-  elif c.p.owner.typ.sons[0] != nil:
+  elif c.p.owner.typ[0] != nil:
     localError(c.config, n.info, errGenerated, "yield statement must yield a value")
 
 proc lookUpForDefined(c: PContext, i: PIdent, onlyCurrentScope: bool): PSym =
@@ -1840,7 +1839,7 @@ proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
     result = nil
     if onlyCurrentScope: return
     checkSonsLen(n, 2, c.config)
-    var m = lookUpForDefined(c, n.sons[0], onlyCurrentScope)
+    var m = lookUpForDefined(c, n[0], onlyCurrentScope)
     if m != nil and m.kind == skModule:
       let ident = considerQuotedIdent(c, n[1], n)
       if m == c.module:
@@ -1852,7 +1851,7 @@ proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
   of nkSym:
     result = n.sym
   of nkOpenSymChoice, nkClosedSymChoice:
-    result = n.sons[0].sym
+    result = n[0].sym
   else:
     localError(c.config, n.info, "identifier expected, but got: " & renderTree(n))
     result = nil
@@ -1864,7 +1863,7 @@ proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode =
   if not onlyCurrentScope and considerQuotedIdent(c, n[0], n).s == "defined":
     let d = considerQuotedIdent(c, n[1], n)
     result.intVal = ord isDefined(c.config, d.s)
-  elif lookUpForDefined(c, n.sons[1], onlyCurrentScope) != nil:
+  elif lookUpForDefined(c, n[1], onlyCurrentScope) != nil:
     result.intVal = 1
   result.info = n.info
   result.typ = getSysType(c.graph, n.info, tyBool)
@@ -1904,14 +1903,14 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
     let expandedSym = expectMacroOrTemplateCall(c, macroCall)
     if expandedSym.kind == skError: return n
 
-    macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
+    macroCall[0] = newSymNode(expandedSym, macroCall.info)
     markUsed(c, n.info, expandedSym)
     onUse(n.info, expandedSym)
 
   if isCallExpr(macroCall):
-    for i in 1 ..< macroCall.len:
-      #if macroCall.sons[0].typ.sons[i].kind != tyUntyped:
-      macroCall.sons[i] = semExprWithType(c, macroCall[i], {})
+    for i in 1..<macroCall.len:
+      #if macroCall[0].typ[i].kind != tyUntyped:
+      macroCall[i] = semExprWithType(c, macroCall[i], {})
     # performing overloading resolution here produces too serious regressions:
     let headSymbol = macroCall[0]
     var cands = 0
@@ -1928,17 +1927,17 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
     elif cands >= 2:
       localError(c.config, n.info, "ambiguous symbol in 'getAst' context: " & $macroCall)
     else:
-      let info = macroCall.sons[0].info
-      macroCall.sons[0] = newSymNode(cand, info)
+      let info = macroCall[0].info
+      macroCall[0] = newSymNode(cand, info)
       markUsed(c, info, cand)
       onUse(info, cand)
 
     # we just perform overloading resolution here:
-    #n.sons[1] = semOverloadedCall(c, macroCall, macroCall, {skTemplate, skMacro})
+    #n[1] = semOverloadedCall(c, macroCall, macroCall, {skTemplate, skMacro})
   else:
     localError(c.config, n.info, "getAst takes a call, but got " & n.renderTree)
   # Preserve the magic symbol in order to be handled in evals.nim
-  internalAssert c.config, n.sons[0].sym.magic == mExpandToAst
+  internalAssert c.config, n[0].sym.magic == mExpandToAst
   #n.typ = getSysSym("NimNode").typ # expandedSym.getReturnType
   if n.kind == nkStmtList and n.len == 1: result = n[0]
   else: result = n
@@ -1946,8 +1945,8 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
 
 proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
                     flags: TExprFlags = {}): PNode =
-  if len(n) == 2:
-    n.sons[0] = newSymNode(magicSym, n.info)
+  if n.len == 2:
+    n[0] = newSymNode(magicSym, n.info)
     result = semExpandToAst(c, n)
   else:
     result = semDirectOp(c, n, flags)
@@ -1969,15 +1968,15 @@ proc processQuotations(c: PContext; n: var PNode, op: string,
       if examinedOp == op:
         returnQuote n[1]
       elif examinedOp.startsWith(op):
-        n.sons[0] = newIdentNode(getIdent(c.cache, examinedOp.substr(op.len)), n.info)
+        n[0] = newIdentNode(getIdent(c.cache, examinedOp.substr(op.len)), n.info)
   elif n.kind == nkAccQuoted and op == "``":
     returnQuote n[0]
   elif n.kind == nkIdent:
     if n.ident.s == "result":
       n = ids[0]
 
-  for i in 0 ..< n.safeLen:
-    processQuotations(c, n.sons[i], op, quotes, ids)
+  for i in 0..<n.safeLen:
+    processQuotations(c, n[i], op, quotes, ids)
 
 proc semQuoteAst(c: PContext, n: PNode): PNode =
   if n.len != 2 and n.len != 3:
@@ -2010,7 +2009,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
               pragmas = c.graph.emptyNode, exceptions = c.graph.emptyNode)
 
   if ids.len > 0:
-    dummyTemplate.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
+    dummyTemplate[paramsPos] = newNodeI(nkFormalParams, n.info)
     dummyTemplate[paramsPos].add getSysSym(c.graph, n.info, "untyped").newSymNode # return type
     ids.add getSysSym(c.graph, n.info, "untyped").newSymNode # params type
     ids.add c.graph.emptyNode # no default value
@@ -2048,7 +2047,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   # open a scope for temporary symbol inclusions:
   let oldScope = c.currentScope
   openScope(c)
-  let oldOwnerLen = len(c.graph.owners)
+  let oldOwnerLen = c.graph.owners.len
   let oldGenerics = c.generics
   let oldErrorOutputs = c.config.m.errorOutputs
   if efExplain notin flags: c.config.m.errorOutputs = {}
@@ -2083,14 +2082,14 @@ 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 len(n) != 2: return semDirectOp(c, n, flags)
+  if n.len != 2: return semDirectOp(c, n, flags)
 
   result = newIntNode(nkIntLit, ord(tryExpr(c, n[1], flags) != nil))
   result.info = n.info
   result.typ = getSysType(c.graph, n.info, tyBool)
 
 proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
-  if len(n) == 3:
+  if n.len == 3:
     # XXX ugh this is really a hack: shallowCopy() can be overloaded only
     # with procs that take not 2 parameters:
     result = newNodeI(nkFastAsgn, n.info)
@@ -2113,7 +2112,7 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType;
     localError(c.config, info, "system needs: nimCreateFlowVar")
   var bindings: TIdTable
   initIdTable(bindings)
-  bindings.idTablePut(sym.ast[genericParamsPos].sons[0].typ, t)
+  bindings.idTablePut(sym.ast[genericParamsPos][0].typ, t)
   result = c.semGenerateInstance(c, sym, bindings, info)
   # since it's an instantiation, we unmark it as a compilerproc. Otherwise
   # codegen would fail:
@@ -2123,15 +2122,15 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType;
 
 proc setMs(n: PNode, s: PSym): PNode =
   result = n
-  n.sons[0] = newSymNode(s)
-  n.sons[0].info = n.info
+  n[0] = newSymNode(s)
+  n[0].info = n.info
 
 proc semSizeof(c: PContext, n: PNode): PNode =
-  if len(n) != 2:
+  if n.len != 2:
     localError(c.config, n.info, errXExpectsTypeOrValue % "sizeof")
   else:
-    n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
-    #restoreOldStyleType(n.sons[1])
+    n[1] = semExprWithType(c, n[1], {efDetermineType})
+    #restoreOldStyleType(n[1])
   n.typ = getSysType(c.graph, n.info, tyInt)
   result = foldSizeOf(c.config, n, n)
 
@@ -2143,7 +2142,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
     markUsed(c, n.info, s)
     checkSonsLen(n, 2, c.config)
     result[0] = newSymNode(s, n[0].info)
-    result[1] = semAddrArg(c, n.sons[1], s.name.s == "unsafeAddr")
+    result[1] = semAddrArg(c, n[1], s.name.s == "unsafeAddr")
     result.typ = makePtrType(c, result[1].typ)
   of mTypeOf:
     markUsed(c, n.info, s)
@@ -2180,9 +2179,9 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
       localError(c.config, n.info, "use the {.experimental.} pragma to enable 'parallel'")
     result = setMs(n, s)
     var x = n.lastSon
-    if x.kind == nkDo: x = x.sons[bodyPos]
+    if x.kind == nkDo: x = x[bodyPos]
     inc c.inParallelStmt
-    result.sons[1] = semStmt(c, x, {})
+    result[1] = semStmt(c, x, {})
     dec c.inParallelStmt
   of mSpawn:
     markUsed(c, n.info, s)
@@ -2191,8 +2190,8 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
       result = n
     else:
       result = setMs(n, s)
-      for i in 1 ..< n.len:
-        result.sons[i] = semExpr(c, n.sons[i])
+      for i in 1..<n.len:
+        result[i] = semExpr(c, n[i])
       let typ = result[^1].typ
       if not typ.isEmptyType:
         if spawnResult(typ, c.inParallelStmt > 0) == srFlowVar:
@@ -2205,7 +2204,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
   of mProcCall:
     markUsed(c, n.info, s)
     result = setMs(n, s)
-    result.sons[1] = semExpr(c, n.sons[1])
+    result[1] = semExpr(c, n[1])
     result.typ = n[1].typ
   of mPlugin:
     markUsed(c, n.info, s)
@@ -2216,7 +2215,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
     if result == nil:
       result = errorNode(c, n)
     else:
-      let callee = result.sons[0].sym
+      let callee = result[0].sym
       if callee.magic == mNone:
         semFinishOperands(c, result)
       activate(c, result)
@@ -2264,41 +2263,41 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
   #   ...
   var whenNimvm = false
   var typ = commonTypeBegin
-  if n.sons.len == 2 and n.sons[0].kind == nkElifBranch and
-      n.sons[1].kind == nkElse:
-    let exprNode = n.sons[0].sons[0]
+  if n.len == 2 and n[0].kind == nkElifBranch and
+      n[1].kind == nkElse:
+    let exprNode = n[0][0]
     if exprNode.kind == nkIdent:
       whenNimvm = lookUp(c, exprNode).magic == mNimvm
     elif exprNode.kind == nkSym:
       whenNimvm = exprNode.sym.magic == mNimvm
     if whenNimvm: n.flags.incl nfLL
 
-  for i in 0 ..< len(n):
-    var it = n.sons[i]
+  for i in 0..<n.len:
+    var it = n[i]
     case it.kind
     of nkElifBranch, nkElifExpr:
       checkSonsLen(it, 2, c.config)
       if whenNimvm:
         if semCheck:
-          it.sons[1] = semExpr(c, it.sons[1])
-          typ = commonType(typ, it.sons[1].typ)
+          it[1] = semExpr(c, it[1])
+          typ = commonType(typ, it[1].typ)
         result = n # when nimvm is not elimited until codegen
       else:
-        let e = forceBool(c, semConstExpr(c, it.sons[0]))
+        let e = forceBool(c, semConstExpr(c, it[0]))
         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[1])
     of nkElse, nkElseExpr:
       checkSonsLen(it, 1, c.config)
       if result == nil or whenNimvm:
         if semCheck:
-          it.sons[0] = semExpr(c, it.sons[0])
-          typ = commonType(typ, it.sons[0].typ)
+          it[0] = semExpr(c, it[0])
+          typ = commonType(typ, it[0].typ)
         if result == nil:
-          result = it.sons[0]
+          result = it[0]
     else: illFormedAst(n, c.config)
   if result == nil:
     result = newNodeI(nkEmpty, n.info)
@@ -2311,58 +2310,58 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
 proc semSetConstr(c: PContext, n: PNode): PNode =
   result = newNodeI(nkCurly, n.info)
   result.typ = newTypeS(tySet, c)
-  if len(n) == 0:
+  if n.len == 0:
     rawAddSon(result.typ, newTypeS(tyEmpty, c))
   else:
     # only semantic checking for all elements, later type checking:
     var typ: PType = nil
-    for i in 0 ..< len(n):
-      if isRange(n.sons[i]):
-        checkSonsLen(n.sons[i], 3, c.config)
-        n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1])
-        n.sons[i].sons[2] = semExprWithType(c, n.sons[i].sons[2])
+    for i in 0..<n.len:
+      if isRange(n[i]):
+        checkSonsLen(n[i], 3, c.config)
+        n[i][1] = semExprWithType(c, n[i][1])
+        n[i][2] = semExprWithType(c, n[i][2])
         if typ == nil:
-          typ = skipTypes(n.sons[i].sons[1].typ,
+          typ = skipTypes(n[i][1].typ,
                           {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
-        n.sons[i].typ = n.sons[i].sons[2].typ # range node needs type too
-      elif n.sons[i].kind == nkRange:
+        n[i].typ = n[i][2].typ # range node needs type too
+      elif n[i].kind == nkRange:
         # already semchecked
         if typ == nil:
-          typ = skipTypes(n.sons[i].sons[0].typ,
+          typ = skipTypes(n[i][0].typ,
                           {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
       else:
-        n.sons[i] = semExprWithType(c, n.sons[i])
+        n[i] = semExprWithType(c, n[i])
         if typ == nil:
-          typ = skipTypes(n.sons[i].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
+          typ = skipTypes(n[i].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
     if not isOrdinalType(typ, allowEnumWithHoles=true):
       localError(c.config, n.info, errOrdinalTypeExpected)
       typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
     elif lengthOrd(c.config, typ) > MaxSetElements:
       typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
     addSonSkipIntLit(result.typ, typ)
-    for i in 0 ..< len(n):
+    for i in 0..<n.len:
       var m: PNode
-      let info = n.sons[i].info
-      if isRange(n.sons[i]):
+      let info = n[i].info
+      if isRange(n[i]):
         m = newNodeI(nkRange, info)
-        addSon(m, fitNode(c, typ, n.sons[i].sons[1], info))
-        addSon(m, fitNode(c, typ, n.sons[i].sons[2], info))
-      elif n.sons[i].kind == nkRange: m = n.sons[i] # already semchecked
+        m.add fitNode(c, typ, n[i][1], info)
+        m.add fitNode(c, typ, n[i][2], info)
+      elif n[i].kind == nkRange: m = n[i] # already semchecked
       else:
-        m = fitNode(c, typ, n.sons[i], info)
-      addSon(result, m)
+        m = fitNode(c, typ, n[i], info)
+      result.add m
 
 proc semTableConstr(c: PContext, n: PNode): PNode =
   # we simply transform ``{key: value, key2, key3: value}`` to
   # ``[(key, value), (key2, value2), (key3, value2)]``
   result = newNodeI(nkBracket, n.info)
   var lastKey = 0
-  for i in 0..n.len-1:
-    var x = n.sons[i]
-    if x.kind == nkExprColonExpr and len(x) == 2:
-      for j in lastKey ..< i:
+  for i in 0..<n.len:
+    var x = n[i]
+    if x.kind == nkExprColonExpr and x.len == 2:
+      for j in lastKey..<i:
         var pair = newNodeI(nkTupleConstr, x.info)
-        pair.add(n.sons[j])
+        pair.add(n[j])
         pair.add(x[1])
         result.add(pair)
 
@@ -2381,25 +2380,24 @@ type
     paNone, paSingle, paTupleFields, paTuplePositions
 
 proc checkPar(c: PContext; n: PNode): TParKind =
-  var length = len(n)
-  if length == 0:
+  if n.len == 0:
     result = paTuplePositions # ()
-  elif length == 1:
-    if n.sons[0].kind == nkExprColonExpr: result = paTupleFields
+  elif n.len == 1:
+    if n[0].kind == nkExprColonExpr: result = paTupleFields
     elif n.kind == nkTupleConstr: result = paTuplePositions
     else: result = paSingle         # (expr)
   else:
-    if n.sons[0].kind == nkExprColonExpr: result = paTupleFields
+    if n[0].kind == nkExprColonExpr: result = paTupleFields
     else: result = paTuplePositions
-    for i in 0 ..< length:
+    for i in 0..<n.len:
       if result == paTupleFields:
-        if (n.sons[i].kind != nkExprColonExpr) or
-            n.sons[i].sons[0].kind notin {nkSym, nkIdent}:
-          localError(c.config, n.sons[i].info, errNamedExprExpected)
+        if (n[i].kind != nkExprColonExpr) or
+            n[i][0].kind notin {nkSym, nkIdent}:
+          localError(c.config, n[i].info, errNamedExprExpected)
           return paNone
       else:
-        if n.sons[i].kind == nkExprColonExpr:
-          localError(c.config, n.sons[i].info, errNamedExprNotAllowed)
+        if n[i].kind == nkExprColonExpr:
+          localError(c.config, n[i].info, errNamedExprNotAllowed)
           return paNone
 
 proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
@@ -2407,35 +2405,35 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
   var typ = newTypeS(tyTuple, c)
   typ.n = newNodeI(nkRecList, n.info) # nkIdentDefs
   var ids = initIntSet()
-  for i in 0 ..< len(n):
+  for i in 0..<n.len:
     if n[i].kind != nkExprColonExpr:
-      illFormedAst(n.sons[i], c.config)
+      illFormedAst(n[i], c.config)
     let id = considerQuotedIdent(c, n[i][0])
     if containsOrIncl(ids, id.id):
-      localError(c.config, n.sons[i].info, errFieldInitTwice % id.s)
-    n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1],
+      localError(c.config, n[i].info, errFieldInitTwice % id.s)
+    n[i][1] = semExprWithType(c, n[i][1],
                                         flags*{efAllowDestructor})
 
-    if n.sons[i].sons[1].typ.kind == tyTypeDesc:
-      localError(c.config, n.sons[i].sons[1].info, "typedesc not allowed as tuple field.")
-      n.sons[i].sons[1].typ = errorType(c)
+    if n[i][1].typ.kind == tyTypeDesc:
+      localError(c.config, n[i][1].info, "typedesc not allowed as tuple field.")
+      n[i][1].typ = errorType(c)
 
-    var f = newSymS(skField, n.sons[i].sons[0], c)
-    f.typ = skipIntLit(n.sons[i].sons[1].typ)
+    var f = newSymS(skField, n[i][0], c)
+    f.typ = skipIntLit(n[i][1].typ)
     f.position = i
     rawAddSon(typ, f.typ)
-    addSon(typ.n, newSymNode(f))
-    n.sons[i].sons[0] = newSymNode(f)
-    addSon(result, n.sons[i])
+    typ.n.add newSymNode(f)
+    n[i][0] = newSymNode(f)
+    result.add n[i]
   result.typ = typ
 
 proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
   result = n                  # we don't modify n, but compute the type:
   result.kind = nkTupleConstr
   var typ = newTypeS(tyTuple, c)  # leave typ.n nil!
-  for i in 0 ..< len(n):
-    n.sons[i] = semExprWithType(c, n.sons[i], flags*{efAllowDestructor})
-    addSonSkipIntLit(typ, n.sons[i].typ)
+  for i in 0..<n.len:
+    n[i] = semExprWithType(c, n[i], flags*{efAllowDestructor})
+    addSonSkipIntLit(typ, n[i].typ)
   result.typ = typ
 
 include semobjconstr
@@ -2445,18 +2443,18 @@ proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode =
   inc(c.p.nestedBlockCounter)
   checkSonsLen(n, 2, c.config)
   openScope(c) # BUGFIX: label is in the scope of block!
-  if n.sons[0].kind != nkEmpty:
-    var labl = newSymG(skLabel, n.sons[0], c)
+  if n[0].kind != nkEmpty:
+    var labl = newSymG(skLabel, n[0], c)
     if sfGenSym notin labl.flags:
       addDecl(c, labl)
     elif labl.owner == nil:
       labl.owner = c.p.owner
-    n.sons[0] = newSymNode(labl, n.sons[0].info)
-    suggestSym(c.config, n.sons[0].info, labl, c.graph.usageSym)
+    n[0] = newSymNode(labl, n[0].info)
+    suggestSym(c.config, n[0].info, labl, c.graph.usageSym)
     styleCheckDef(c.config, labl)
     onDef(n[0].info, labl)
-  n.sons[1] = semExpr(c, n.sons[1], flags)
-  n.typ = n.sons[1].typ
+  n[1] = semExpr(c, n[1], flags)
+  n.typ = n[1].typ
   if isEmptyType(n.typ): n.kind = nkBlockStmt
   else: n.kind = nkBlockExpr
   closeScope(c)
@@ -2484,7 +2482,7 @@ proc semExportExcept(c: PContext, n: PNode): PNode =
 proc semExport(c: PContext, n: PNode): PNode =
   result = newNodeI(nkExportStmt, n.info)
   for i in 0..<n.len:
-    let a = n.sons[i]
+    let a = n[i]
     var o: TOverloadIter
     var s = initOverloadIter(o, c, a)
     if s == nil:
@@ -2517,7 +2515,7 @@ proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
   if tupexp.len > 0: # don't interpret () as type
     isTupleType = tupexp[0].typ.kind == tyTypeDesc
     # check if either everything or nothing is tyTypeDesc
-    for i in 1 ..< tupexp.len:
+    for i in 1..<tupexp.len:
       if isTupleType != (tupexp[i].typ.kind == tyTypeDesc):
         localError(c.config, tupexp[i].info, "Mixing types and values in tuples is not allowed.")
         return(errorNode(c,n))
@@ -2530,7 +2528,7 @@ proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
 
 proc shouldBeBracketExpr(n: PNode): bool =
   assert n.kind in nkCallKinds
-  let a = n.sons[0]
+  let a = n[0]
   if a.kind in nkCallKinds:
     let b = a[0]
     if b.kind in nkSymChoices:
@@ -2538,7 +2536,7 @@ proc shouldBeBracketExpr(n: PNode): bool =
         if b[i].kind == nkSym and b[i].sym.magic == mArrGet:
           let be = newNodeI(nkBracketExpr, n.info)
           for i in 1..<a.len: be.add(a[i])
-          n.sons[0] = be
+          n[0] = be
           return true
 
 proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
@@ -2614,7 +2612,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
       result = semExpr(c, result, flags)
   of nkBind:
     message(c.config, n.info, warnDeprecated, "bind is deprecated")
-    result = semExpr(c, n.sons[0], flags)
+    result = semExpr(c, n[0], flags)
   of nkTypeOfExpr, nkTupleTy, nkTupleClassTy, nkRefTy..nkEnumTy, nkStaticTy:
     if c.matchedConcept != nil and n.len == 1:
       let modifier = n.modifierTypeKindOfNode
@@ -2630,10 +2628,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     #when defined(nimsuggest):
     #  if gIdeCmd == ideCon and c.config.m.trackPos == n.info: suggestExprNoCheck(c, n)
     let mode = if nfDotField in n.flags: {} else: {checkUndeclared}
-    var s = qualifiedLookUp(c, n.sons[0], mode)
+    var s = qualifiedLookUp(c, n[0], mode)
     if s != nil:
-      #if c.config.cmd == cmdPretty and n.sons[0].kind == nkDotExpr:
-      #  pretty.checkUse(n.sons[0].sons[1].info, s)
+      #if c.config.cmd == cmdPretty and n[0].kind == nkDotExpr:
+      #  pretty.checkUse(n[0][1].info, s)
       case s.kind
       of skMacro, skTemplate:
         result = semDirectOp(c, n, flags)
@@ -2658,9 +2656,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
         isSymChoice(n[0][0]):
       # indirectOp can deal with explicit instantiations; the fixes
       # the 'newSeq[T](x)' bug
-      setGenericParams(c, n.sons[0])
+      setGenericParams(c, n[0])
       result = semDirectOp(c, n, flags)
-    elif isSymChoice(n.sons[0]) or nfDotField in n.flags:
+    elif isSymChoice(n[0]) or nfDotField in n.flags:
       result = semDirectOp(c, n, flags)
     else:
       result = semIndirectOp(c, n, flags)
@@ -2702,7 +2700,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     of paNone: result = errorNode(c, n)
     of paTuplePositions: result = semTupleConstr(c, n, flags)
     of paTupleFields: result = semTupleFieldsConstr(c, n, flags)
-    of paSingle: result = semExpr(c, n.sons[0], flags)
+    of paSingle: result = semExpr(c, n[0], flags)
   of nkCurly: result = semSetConstr(c, n)
   of nkBracket: result = semArrayConstr(c, n, flags)
   of nkObjConstr: result = semObjConstr(c, n, flags)
@@ -2711,11 +2709,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkAddr:
     result = n
     checkSonsLen(n, 1, c.config)
-    result[0] = semAddrArg(c, n.sons[0])
+    result[0] = semAddrArg(c, n[0])
     result.typ = makePtrType(c, result[0].typ)
   of nkHiddenAddr, nkHiddenDeref:
     checkSonsLen(n, 1, c.config)
-    n.sons[0] = semExpr(c, n.sons[0], flags)
+    n[0] = semExpr(c, n[0], flags)
   of nkCast: result = semCast(c, n)
   of nkIfExpr, nkIfStmt: result = semIf(c, n, flags)
   of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv:
@@ -2795,14 +2793,14 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkDefer:
     if c.currentScope == c.topLevelScope:
       localError(c.config, n.info, "defer statement not supported at top level")
-    n.sons[0] = semExpr(c, n.sons[0])
-    if not n.sons[0].typ.isEmptyType and not implicitlyDiscardable(n.sons[0]):
+    n[0] = semExpr(c, n[0])
+    if not n[0].typ.isEmptyType and not implicitlyDiscardable(n[0]):
       localError(c.config, n.info, "'defer' takes a 'void' expression")
     #localError(c.config, n.info, errGenerated, "'defer' not allowed in this context")
   of nkGotoState, nkState:
     if n.len != 1 and n.len != 2: illFormedAst(n, c.config)
-    for i in 0 ..< n.len:
-      n.sons[i] = semExpr(c, n.sons[i])
+    for i in 0..<n.len:
+      n[i] = semExpr(c, n[i])
   of nkComesFrom: discard "ignore the comes from information for now"
   else:
     localError(c.config, n.info, "invalid expression: " &
diff --git a/compiler/semfields.nim b/compiler/semfields.nim
index 1480374dd..a911ae823 100644
--- a/compiler/semfields.nim
+++ b/compiler/semfields.nim
@@ -27,19 +27,18 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
   of nkIdent, nkSym:
     result = n
     let ident = considerQuotedIdent(c.c, n)
-    var L = len(forLoop)
     if c.replaceByFieldName:
       if ident.id == considerQuotedIdent(c.c, forLoop[0]).id:
         let fieldName = if c.tupleType.isNil: c.field.name.s
                         elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
-                        else: c.tupleType.n.sons[c.tupleIndex].sym.name.s
+                        else: c.tupleType.n[c.tupleIndex].sym.name.s
         result = newStrNode(nkStrLit, fieldName)
         return
     # other fields:
-    for i in ord(c.replaceByFieldName)..L-3:
+    for i in ord(c.replaceByFieldName)..<forLoop.len-2:
       if ident.id == considerQuotedIdent(c.c, forLoop[i]).id:
-        var call = forLoop.sons[L-2]
-        var tupl = call.sons[i+1-ord(c.replaceByFieldName)]
+        var call = forLoop[^2]
+        var tupl = call[i+1-ord(c.replaceByFieldName)]
         if c.field.isNil:
           result = newNodeI(nkBracketExpr, n.info)
           result.add(tupl)
@@ -54,9 +53,9 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
       localError(c.c.config, n.info,
                  "'continue' not supported in a 'fields' loop")
     result = copyNode(n)
-    newSons(result, len(n))
-    for i in 0 ..< len(n):
-      result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop)
+    newSons(result, n.len)
+    for i in 0..<n.len:
+      result[i] = instFieldLoopBody(c, n[i], forLoop)
 
 type
   TFieldsCtx = object
@@ -78,8 +77,7 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
     closeScope(c.c)
   of nkNilLit: discard
   of nkRecCase:
-    let L = forLoop.len
-    let call = forLoop.sons[L-2]
+    let call = forLoop[^2]
     if call.len > 2:
       localError(c.c.config, forLoop.info,
                  "parallel 'fields' iterator does not work for 'case' objects")
@@ -90,15 +88,14 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
     var caseStmt = newNodeI(nkCaseStmt, forLoop.info)
     # generate selector:
     var access = newNodeI(nkDotExpr, forLoop.info, 2)
-    access.sons[0] = call.sons[1]
-    access.sons[1] = newSymNode(typ.sons[0].sym, forLoop.info)
+    access[0] = call[1]
+    access[1] = newSymNode(typ[0].sym, forLoop.info)
     caseStmt.add(semExprWithType(c.c, access))
     # copy the branches over, but replace the fields with the for loop body:
-    for i in 1 ..< typ.len:
+    for i in 1..<typ.len:
       var branch = copyTree(typ[i])
-      let L = branch.len
-      branch.sons[L-1] = newNodeI(nkStmtList, forLoop.info)
-      semForObjectFields(c, typ[i].lastSon, forLoop, branch[L-1])
+      branch[^1] = newNodeI(nkStmtList, forLoop.info)
+      semForObjectFields(c, typ[i].lastSon, forLoop, branch[^1])
       caseStmt.add(branch)
     father.add(caseStmt)
   of nkRecList:
@@ -116,30 +113,29 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
     trueSymbol = newSym(skUnknown, getIdent(c.cache, "true"), getCurrOwner(c), n.info)
     trueSymbol.typ = getSysType(c.graph, n.info, tyBool)
 
-  result.sons[0] = newSymNode(trueSymbol, n.info)
+  result[0] = newSymNode(trueSymbol, n.info)
   var stmts = newNodeI(nkStmtList, n.info)
-  result.sons[1] = stmts
+  result[1] = stmts
 
-  var length = len(n)
-  var call = n.sons[length-2]
-  if length-2 != len(call)-1 + ord(m==mFieldPairs):
+  var call = n[^2]
+  if n.len-2 != call.len-1 + ord(m==mFieldPairs):
     localError(c.config, n.info, errWrongNumberOfVariables)
     return result
 
   const skippedTypesForFields = abstractVar - {tyTypeDesc} + tyUserTypeClasses
-  var tupleTypeA = skipTypes(call.sons[1].typ, skippedTypesForFields)
+  var tupleTypeA = skipTypes(call[1].typ, skippedTypesForFields)
   if tupleTypeA.kind notin {tyTuple, tyObject}:
     localError(c.config, n.info, errGenerated, "no object or tuple type")
     return result
-  for i in 1..call.len-1:
-    var tupleTypeB = skipTypes(call.sons[i].typ, skippedTypesForFields)
+  for i in 1..<call.len:
+    var tupleTypeB = skipTypes(call[i].typ, skippedTypesForFields)
     if not sameType(tupleTypeA, tupleTypeB):
-      typeMismatch(c.config, call.sons[i].info, tupleTypeA, tupleTypeB)
+      typeMismatch(c.config, call[i].info, tupleTypeA, tupleTypeB)
 
   inc(c.p.nestedLoopCounter)
   if tupleTypeA.kind == tyTuple:
-    var loopBody = n.sons[length-1]
-    for i in 0..len(tupleTypeA)-1:
+    var loopBody = n[^1]
+    for i in 0..<tupleTypeA.len:
       openScope(c)
       var fc: TFieldInstCtx
       fc.tupleType = tupleTypeA
@@ -158,8 +154,8 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
     var t = tupleTypeA
     while t.kind == tyObject:
       semForObjectFields(fc, t.n, n, stmts)
-      if t.sons[0] == nil: break
-      t = skipTypes(t.sons[0], skipPtrs)
+      if t[0] == nil: break
+      t = skipTypes(t[0], skipPtrs)
   dec(c.p.nestedLoopCounter)
   # for TR macros this 'while true: ...; break' loop is pretty bad, so
   # we avoid it now if we can:
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index ec2d646c8..bacc5e9c6 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -104,9 +104,9 @@ proc ordinalValToString*(a: PNode; g: ModuleGraph): string =
     result = $chr(toInt64(x) and 0xff)
   of tyEnum:
     var n = t.n
-    for i in 0 ..< len(n):
-      if n.sons[i].kind != nkSym: internalError(g.config, a.info, "ordinalValToString")
-      var field = n.sons[i].sym
+    for i in 0..<n.len:
+      if n[i].kind != nkSym: internalError(g.config, a.info, "ordinalValToString")
+      var field = n[i].sym
       if field.position == x:
         if field.ast == nil:
           return field.name.s
@@ -119,10 +119,10 @@ proc ordinalValToString*(a: PNode; g: ModuleGraph): string =
     result = $x
 
 proc isFloatRange(t: PType): bool {.inline.} =
-  result = t.kind == tyRange and t.sons[0].kind in {tyFloat..tyFloat128}
+  result = t.kind == tyRange and t[0].kind in {tyFloat..tyFloat128}
 
 proc isIntRange(t: PType): bool {.inline.} =
-  result = t.kind == tyRange and t.sons[0].kind in {
+  result = t.kind == tyRange and t[0].kind in {
       tyInt..tyInt64, tyUInt8..tyUInt32}
 
 proc pickIntRange(a, b: PType): PType =
@@ -144,16 +144,16 @@ proc makeRange(typ: PType, first, last: BiggestInt; g: ModuleGraph): PType =
     result = typ
   else:
     var n = newNode(nkRange)
-    addSon(n, lowerNode)
-    addSon(n, newIntNode(nkIntLit, maxA))
+    n.add lowerNode
+    n.add newIntNode(nkIntLit, maxA)
     result = newType(tyRange, typ.owner)
     result.n = n
     addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
 
 proc makeRangeF(typ: PType, first, last: BiggestFloat; g: ModuleGraph): PType =
   var n = newNode(nkRange)
-  addSon(n, newFloatNode(nkFloatLit, min(first.float, last.float)))
-  addSon(n, newFloatNode(nkFloatLit, max(first.float, last.float)))
+  n.add newFloatNode(nkFloatLit, min(first.float, last.float))
+  n.add newFloatNode(nkFloatLit, max(first.float, last.float))
   result = newType(tyRange, typ.owner)
   result.n = n
   addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
@@ -194,7 +194,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
     elif a.kind in {nkStrLit..nkTripleStrLit}:
       result = newIntNodeT(toInt128(a.strVal.len), n, g)
     else:
-      result = newIntNodeT(toInt128(len(a)), n, g)
+      result = newIntNodeT(toInt128(a.len), n, g)
   of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
   # XXX: Hides overflow/underflow
   of mAbsI: result = foldAbs(getInt(a), n, g)
@@ -372,17 +372,17 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
 
 proc getConstIfExpr(c: PSym, n: PNode; g: ModuleGraph): PNode =
   result = nil
-  for i in 0 ..< len(n):
-    var it = n.sons[i]
+  for i in 0..<n.len:
+    var it = n[i]
     if it.len == 2:
-      var e = getConstExpr(c, it.sons[0], g)
+      var e = getConstExpr(c, it[0], g)
       if e == nil: return nil
       if getOrdValue(e) != 0:
         if result == nil:
-          result = getConstExpr(c, it.sons[1], g)
+          result = getConstExpr(c, it[1], g)
           if result == nil: return
     elif it.len == 1:
-      if result == nil: result = getConstExpr(c, it.sons[0], g)
+      if result == nil: result = getConstExpr(c, it[0], g)
     else: internalError(g.config, it.info, "getConstIfExpr()")
 
 proc leValueConv*(a, b: PNode): bool =
@@ -401,17 +401,17 @@ proc leValueConv*(a, b: PNode): bool =
   else: result = false # internalError(a.info, "leValueConv")
 
 proc magicCall(m: PSym, n: PNode; g: ModuleGraph): PNode =
-  if len(n) <= 1: return
+  if n.len <= 1: return
 
-  var s = n.sons[0].sym
-  var a = getConstExpr(m, n.sons[1], g)
+  var s = n[0].sym
+  var a = getConstExpr(m, n[1], g)
   var b, c: PNode
   if a == nil: return
-  if len(n) > 2:
-    b = getConstExpr(m, n.sons[2], g)
+  if n.len > 2:
+    b = getConstExpr(m, n[2], g)
     if b == nil: return
-    if len(n) > 3:
-      c = getConstExpr(m, n.sons[3], g)
+    if n.len > 3:
+      c = getConstExpr(m, n[3], g)
       if c == nil: return
   result = evalOp(s.magic, n, a, b, c, g)
 
@@ -478,58 +478,58 @@ proc getArrayConstr(m: PSym, n: PNode; g: ModuleGraph): PNode =
     if result == nil: result = n
 
 proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
-  var x = getConstExpr(m, n.sons[0], g)
+  var x = getConstExpr(m, n[0], g)
   if x == nil or x.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyTypeDesc:
     return
 
-  var y = getConstExpr(m, n.sons[1], g)
+  var y = getConstExpr(m, n[1], g)
   if y == nil: return
 
   var idx = toInt64(getOrdValue(y))
   case x.kind
   of nkPar, nkTupleConstr:
-    if idx >= 0 and idx < len(x):
+    if idx >= 0 and idx < x.len:
       result = x.sons[idx]
-      if result.kind == nkExprColonExpr: result = result.sons[1]
+      if result.kind == nkExprColonExpr: result = result[1]
     else:
-      localError(g.config, n.info, formatErrorIndexBound(idx, len(x)-1) & $n)
+      localError(g.config, n.info, formatErrorIndexBound(idx, x.len-1) & $n)
   of nkBracket:
     idx = idx - toInt64(firstOrd(g.config, x.typ))
-    if idx >= 0 and idx < x.len: result = x.sons[int(idx)]
+    if idx >= 0 and idx < x.len: result = x[int(idx)]
     else: localError(g.config, n.info, formatErrorIndexBound(idx, x.len-1) & $n)
   of nkStrLit..nkTripleStrLit:
     result = newNodeIT(nkCharLit, x.info, n.typ)
-    if idx >= 0 and idx < len(x.strVal):
+    if idx >= 0 and idx < x.strVal.len:
       result.intVal = ord(x.strVal[int(idx)])
-    elif idx == len(x.strVal) and optLaxStrings in g.config.options:
+    elif idx == x.strVal.len and optLaxStrings in g.config.options:
       discard
     else:
-      localError(g.config, n.info, formatErrorIndexBound(idx, len(x.strVal)-1) & $n)
+      localError(g.config, n.info, formatErrorIndexBound(idx, x.strVal.len-1) & $n)
   else: discard
 
 proc foldFieldAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
   # a real field access; proc calls have already been transformed
-  var x = getConstExpr(m, n.sons[0], g)
+  var x = getConstExpr(m, n[0], g)
   if x == nil or x.kind notin {nkObjConstr, nkPar, nkTupleConstr}: return
 
-  var field = n.sons[1].sym
-  for i in ord(x.kind == nkObjConstr) ..< len(x):
-    var it = x.sons[i]
+  var field = n[1].sym
+  for i in ord(x.kind == nkObjConstr)..<x.len:
+    var it = x[i]
     if it.kind != nkExprColonExpr:
       # lookup per index:
-      result = x.sons[field.position]
-      if result.kind == nkExprColonExpr: result = result.sons[1]
+      result = x[field.position]
+      if result.kind == nkExprColonExpr: result = result[1]
       return
-    if it.sons[0].sym.name.id == field.name.id:
-      result = x.sons[i].sons[1]
+    if it[0].sym.name.id == field.name.id:
+      result = x[i][1]
       return
   localError(g.config, n.info, "field not found: " & field.name.s)
 
 proc foldConStrStr(m: PSym, n: PNode; g: ModuleGraph): PNode =
   result = newNodeIT(nkStrLit, n.info, n.typ)
   result.strVal = ""
-  for i in 1 ..< len(n):
-    let a = getConstExpr(m, n.sons[i], g)
+  for i in 1..<n.len:
+    let a = getConstExpr(m, n[i], g)
     if a == nil: return nil
     result.strVal.add(getStrOrChar(a))
 
@@ -606,8 +606,8 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
   of nkIfExpr:
     result = getConstIfExpr(m, n, g)
   of nkCallKinds:
-    if n.sons[0].kind != nkSym: return
-    var s = n.sons[0].sym
+    if n[0].kind != nkSym: return
+    var s = n[0].sym
     if s.kind != skProc and s.kind != skFunc: return
     try:
       case s.magic
@@ -615,33 +615,33 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
         # If it has no sideEffect, it should be evaluated. But not here.
         return
       of mLow:
-        if skipTypes(n.sons[1].typ, abstractVarRange).kind in tyFloat..tyFloat64:
-          result = newFloatNodeT(firstFloat(n.sons[1].typ), n, g)
+        if skipTypes(n[1].typ, abstractVarRange).kind in tyFloat..tyFloat64:
+          result = newFloatNodeT(firstFloat(n[1].typ), n, g)
         else:
-          result = newIntNodeT(firstOrd(g.config, n.sons[1].typ), n, g)
+          result = newIntNodeT(firstOrd(g.config, n[1].typ), n, g)
       of mHigh:
-        if skipTypes(n.sons[1].typ, abstractVar+{tyUserTypeClassInst}).kind notin
+        if skipTypes(n[1].typ, abstractVar+{tyUserTypeClassInst}).kind notin
             {tySequence, tyString, tyCString, tyOpenArray, tyVarargs}:
-          if skipTypes(n.sons[1].typ, abstractVarRange).kind in tyFloat..tyFloat64:
-            result = newFloatNodeT(lastFloat(n.sons[1].typ), n, g)
+          if skipTypes(n[1].typ, abstractVarRange).kind in tyFloat..tyFloat64:
+            result = newFloatNodeT(lastFloat(n[1].typ), n, g)
           else:
             result = newIntNodeT(lastOrd(g.config, skipTypes(n[1].typ, abstractVar)), n, g)
         else:
-          var a = getArrayConstr(m, n.sons[1], g)
+          var a = getArrayConstr(m, n[1], g)
           if a.kind == nkBracket:
             # we can optimize it away:
-            result = newIntNodeT(toInt128(len(a)-1), n, g)
+            result = newIntNodeT(toInt128(a.len-1), n, g)
       of mLengthOpenArray:
-        var a = getArrayConstr(m, n.sons[1], g)
+        var a = getArrayConstr(m, n[1], g)
         if a.kind == nkBracket:
           # we can optimize it away! This fixes the bug ``len(134)``.
-          result = newIntNodeT(toInt128(len(a)), n, g)
+          result = newIntNodeT(toInt128(a.len), n, g)
         else:
           result = magicCall(m, n, g)
       of mLengthArray:
         # It doesn't matter if the argument is const or not for mLengthArray.
         # This fixes bug #544.
-        result = newIntNodeT(lengthOrd(g.config, n.sons[1].typ), n, g)
+        result = newIntNodeT(lengthOrd(g.config, n[1].typ), n, g)
       of mSizeOf:
         result = foldSizeOf(g.config, n, nil)
       of mAlignOf:
@@ -663,10 +663,10 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
     except DivByZeroError:
       localError(g.config, n.info, "division by zero")
   of nkAddr:
-    var a = getConstExpr(m, n.sons[0], g)
+    var a = getConstExpr(m, n[0], g)
     if a != nil:
       result = n
-      n.sons[0] = a
+      n[0] = a
   of nkBracket, nkCurly:
     result = copyNode(n)
     for i, son in n.pairs:
@@ -675,24 +675,24 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
       result.add a
     incl(result.flags, nfAllConst)
   of nkRange:
-    var a = getConstExpr(m, n.sons[0], g)
+    var a = getConstExpr(m, n[0], g)
     if a == nil: return
-    var b = getConstExpr(m, n.sons[1], g)
+    var b = getConstExpr(m, n[1], g)
     if b == nil: return
     result = copyNode(n)
-    addSon(result, a)
-    addSon(result, b)
+    result.add a
+    result.add b
   #of nkObjConstr:
   #  result = copyTree(n)
-  #  for i in 1 ..< len(n):
-  #    var a = getConstExpr(m, n.sons[i].sons[1])
+  #  for i in 1..<n.len:
+  #    var a = getConstExpr(m, n[i][1])
   #    if a == nil: return nil
-  #    result.sons[i].sons[1] = a
+  #    result[i][1] = a
   #  incl(result.flags, nfAllConst)
   of nkPar, nkTupleConstr:
     # tuple constructor
     result = copyNode(n)
-    if (len(n) > 0) and (n.sons[0].kind == nkExprColonExpr):
+    if (n.len > 0) and (n[0].kind == nkExprColonExpr):
       for i, expr in n.pairs:
         let exprNew = copyNode(expr) # nkExprColonExpr
         exprNew.add expr[0]
@@ -707,26 +707,26 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
         result.add a
     incl(result.flags, nfAllConst)
   of nkChckRangeF, nkChckRange64, nkChckRange:
-    var a = getConstExpr(m, n.sons[0], g)
+    var a = getConstExpr(m, n[0], g)
     if a == nil: return
-    if leValueConv(n.sons[1], a) and leValueConv(a, n.sons[2]):
+    if leValueConv(n[1], a) and leValueConv(a, n[2]):
       result = a              # a <= x and x <= b
       result.typ = n.typ
     else:
       localError(g.config, n.info,
         "conversion from $1 to $2 is invalid" %
-          [typeToString(n.sons[0].typ), typeToString(n.typ)])
+          [typeToString(n[0].typ), typeToString(n.typ)])
   of nkStringToCString, nkCStringToString:
-    var a = getConstExpr(m, n.sons[0], g)
+    var a = getConstExpr(m, n[0], g)
     if a == nil: return
     result = a
     result.typ = n.typ
   of nkHiddenStdConv, nkHiddenSubConv, nkConv:
-    var a = getConstExpr(m, n.sons[1], g)
+    var a = getConstExpr(m, n[1], g)
     if a == nil: return
     result = foldConv(n, a, g, check=true)
   of nkCast:
-    var a = getConstExpr(m, n.sons[1], g)
+    var a = getConstExpr(m, n[1], g)
     if a == nil: return
     if n.typ != nil and n.typ.kind in NilableTypes:
       # we allow compile-time 'cast' for pointer types:
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index 89051ec4c..59be8d597 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -19,8 +19,8 @@
 
 proc getIdentNode(c: PContext; n: PNode): PNode =
   case n.kind
-  of nkPostfix: result = getIdentNode(c, n.sons[1])
-  of nkPragmaExpr: result = getIdentNode(c, n.sons[0])
+  of nkPostfix: result = getIdentNode(c, n[1])
+  of nkPragmaExpr: result = getIdentNode(c, n[0])
   of nkIdent, nkAccQuoted, nkSym: result = n
   else:
     illFormedAst(n, c.config)
@@ -134,7 +134,7 @@ proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
 
 proc newDot(n, b: PNode): PNode =
   result = newNodeI(nkDotExpr, n.info)
-  result.add(n.sons[0])
+  result.add(n[0])
   result.add(b)
 
 proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
@@ -148,7 +148,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
   if s != nil:
     result = semGenericStmtSymbol(c, n, s, ctx, flags)
   else:
-    n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx)
+    n[0] = semGenericStmt(c, n[0], flags, ctx)
     result = n
     let n = n[1]
     let ident = considerQuotedIdent(c, n)
@@ -208,13 +208,13 @@ proc semGenericStmt(c: PContext, n: PNode,
     # in the generic instantiation process...
     discard
   of nkBind:
-    result = semGenericStmt(c, n.sons[0], flags+{withinBind}, ctx)
+    result = semGenericStmt(c, n[0], flags+{withinBind}, ctx)
   of nkMixinStmt:
     result = semMixinStmt(c, n, ctx.toMixin)
   of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit:
     # check if it is an expression macro:
     checkMinSonsLen(n, 1, c.config)
-    let fn = n.sons[0]
+    let fn = n[0]
     var s = qualifiedLookUp(c, fn, {})
     if s == nil and
         {withinMixin, withinConcept}*flags == {} and
@@ -235,7 +235,7 @@ proc semGenericStmt(c: PContext, n: PNode,
           result = semMacroExpr(c, n, n, s, {efNoSemCheck})
           result = semGenericStmt(c, result, flags, ctx)
         else:
-          n.sons[0] = sc
+          n[0] = sc
           result = n
         mixinContext = true
       of skTemplate:
@@ -244,7 +244,7 @@ proc semGenericStmt(c: PContext, n: PNode,
           result = semTemplateExpr(c, n, s, {efNoSemCheck})
           result = semGenericStmt(c, result, flags, ctx)
         else:
-          n.sons[0] = sc
+          n[0] = sc
           result = n
         # BUGFIX: we must not return here, we need to do first phase of
         # symbol lookup. Also since templates and macros can do scope injections
@@ -255,242 +255,236 @@ proc semGenericStmt(c: PContext, n: PNode,
         # Leave it as an identifier.
         discard
       of skProc, skFunc, skMethod, skIterator, skConverter, skModule:
-        result.sons[0] = sc
+        result[0] = sc
         first = 1
         # We're not interested in the example code during this pass so let's
         # skip it
         if s.magic == mRunnableExamples:
           inc first
       of skGenericParam:
-        result.sons[0] = newSymNodeTypeDesc(s, fn.info)
+        result[0] = newSymNodeTypeDesc(s, fn.info)
         onUse(fn.info, s)
         first = 1
       of skType:
         # bad hack for generics:
         if (s.typ != nil) and (s.typ.kind != tyGenericParam):
-          result.sons[0] = newSymNodeTypeDesc(s, fn.info)
+          result[0] = newSymNodeTypeDesc(s, fn.info)
           onUse(fn.info, s)
           first = 1
       else:
-        result.sons[0] = newSymNode(s, fn.info)
+        result[0] = newSymNode(s, fn.info)
         onUse(fn.info, s)
         first = 1
     elif fn.kind == nkDotExpr:
-      result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
+      result[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
       first = 1
     # Consider 'when declared(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
     # in threads.nim: the subtle preprocessing here binds 'globalsSlot' which
     # is not exported and yet the generic 'threadProcWrapper' works correctly.
     let flags = if mixinContext: flags+{withinMixin} else: flags
-    for i in first ..< safeLen(result):
-      result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx)
+    for i in first..<result.safeLen:
+      result[i] = semGenericStmt(c, result[i], flags, ctx)
   of nkCurlyExpr:
     result = newNodeI(nkCall, n.info)
     result.add newIdentNode(getIdent(c.cache, "{}"), n.info)
-    for i in 0 ..< n.len: result.add(n[i])
+    for i in 0..<n.len: result.add(n[i])
     result = semGenericStmt(c, result, flags, ctx)
   of nkBracketExpr:
     result = newNodeI(nkCall, n.info)
     result.add newIdentNode(getIdent(c.cache, "[]"), n.info)
-    for i in 0 ..< n.len: result.add(n[i])
-    withBracketExpr ctx, n.sons[0]:
+    for i in 0..<n.len: result.add(n[i])
+    withBracketExpr ctx, n[0]:
       result = semGenericStmt(c, result, flags, ctx)
   of nkAsgn, nkFastAsgn:
     checkSonsLen(n, 2, c.config)
-    let a = n.sons[0]
-    let b = n.sons[1]
+    let a = n[0]
+    let b = n[1]
 
     let k = a.kind
     case k
     of nkCurlyExpr:
       result = newNodeI(nkCall, n.info)
       result.add newIdentNode(getIdent(c.cache, "{}="), n.info)
-      for i in 0 ..< a.len: result.add(a[i])
+      for i in 0..<a.len: result.add(a[i])
       result.add(b)
       result = semGenericStmt(c, result, flags, ctx)
     of nkBracketExpr:
       result = newNodeI(nkCall, n.info)
       result.add newIdentNode(getIdent(c.cache, "[]="), n.info)
-      for i in 0 ..< a.len: result.add(a[i])
+      for i in 0..<a.len: result.add(a[i])
       result.add(b)
-      withBracketExpr ctx, a.sons[0]:
+      withBracketExpr ctx, a[0]:
         result = semGenericStmt(c, result, flags, ctx)
     else:
-      for i in 0 ..< len(n):
-        result.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
+      for i in 0..<n.len:
+        result[i] = semGenericStmt(c, n[i], flags, ctx)
   of nkIfStmt:
-    for i in 0 ..< len(n):
-      n.sons[i] = semGenericStmtScope(c, n.sons[i], flags, ctx)
+    for i in 0..<n.len:
+      n[i] = semGenericStmtScope(c, n[i], flags, ctx)
   of nkWhenStmt:
-    for i in 0 ..< len(n):
+    for i in 0..<n.len:
       # bug #8603: conditions of 'when' statements are not
       # in a 'mixin' context:
       let it = n[i]
       if it.kind in {nkElifExpr, nkElifBranch}:
-        n.sons[i].sons[0] = semGenericStmt(c, it[0], flags, ctx)
-        n.sons[i].sons[1] = semGenericStmt(c, it[1], flags+{withinMixin}, ctx)
+        n[i][0] = semGenericStmt(c, it[0], flags, ctx)
+        n[i][1] = semGenericStmt(c, it[1], flags+{withinMixin}, ctx)
       else:
-        n.sons[i] = semGenericStmt(c, it, flags+{withinMixin}, ctx)
+        n[i] = semGenericStmt(c, it, flags+{withinMixin}, ctx)
   of nkWhileStmt:
     openScope(c)
-    for i in 0 ..< len(n):
-      n.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
+    for i in 0..<n.len:
+      n[i] = semGenericStmt(c, n[i], flags, ctx)
     closeScope(c)
   of nkCaseStmt:
     openScope(c)
-    n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx)
-    for i in 1 ..< len(n):
-      var a = n.sons[i]
+    n[0] = semGenericStmt(c, n[0], flags, ctx)
+    for i in 1..<n.len:
+      var a = n[i]
       checkMinSonsLen(a, 1, c.config)
-      var L = len(a)
-      for j in 0 .. L-2:
-        a.sons[j] = semGenericStmt(c, a.sons[j], flags, ctx)
-      a.sons[L - 1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx)
+      for j in 0..<a.len-1:
+        a[j] = semGenericStmt(c, a[j], flags, ctx)
+      a[^1] = semGenericStmtScope(c, a[^1], flags, ctx)
     closeScope(c)
   of nkForStmt, nkParForStmt:
-    var L = len(n)
     openScope(c)
-    n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, ctx)
-    for i in 0 .. L - 3:
-      if (n.sons[i].kind == nkVarTuple):
-        for s in n.sons[i]:
+    n[^2] = semGenericStmt(c, n[^2], flags, ctx)
+    for i in 0..<n.len - 2:
+      if (n[i].kind == nkVarTuple):
+        for s in n[i]:
           if (s.kind == nkIdent):
             addTempDecl(c,s,skForVar)
       else:
-        addTempDecl(c, n.sons[i], skForVar)
+        addTempDecl(c, n[i], skForVar)
     openScope(c)
-    n.sons[L - 1] = semGenericStmt(c, n.sons[L-1], flags, ctx)
+    n[^1] = semGenericStmt(c, n[^1], flags, ctx)
     closeScope(c)
     closeScope(c)
   of nkBlockStmt, nkBlockExpr, nkBlockType:
     checkSonsLen(n, 2, c.config)
     openScope(c)
-    if n.sons[0].kind != nkEmpty:
-      addTempDecl(c, n.sons[0], skLabel)
-    n.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
+    if n[0].kind != nkEmpty:
+      addTempDecl(c, n[0], skLabel)
+    n[1] = semGenericStmt(c, n[1], flags, ctx)
     closeScope(c)
   of nkTryStmt, nkHiddenTryStmt:
     checkMinSonsLen(n, 2, c.config)
-    n.sons[0] = semGenericStmtScope(c, n.sons[0], flags, ctx)
-    for i in 1 ..< len(n):
-      var a = n.sons[i]
+    n[0] = semGenericStmtScope(c, n[0], flags, ctx)
+    for i in 1..<n.len:
+      var a = n[i]
       checkMinSonsLen(a, 1, c.config)
-      var L = len(a)
       openScope(c)
-      for j in 0 .. L-2:
-        if a.sons[j].isInfixAs():
-          addTempDecl(c, getIdentNode(c, a.sons[j][2]), skLet)
-          a.sons[j].sons[1] = semGenericStmt(c, a.sons[j][1], flags+{withinTypeDesc}, ctx)
+      for j in 0..<a.len-1:
+        if a[j].isInfixAs():
+          addTempDecl(c, getIdentNode(c, a[j][2]), skLet)
+          a[j][1] = semGenericStmt(c, a[j][1], flags+{withinTypeDesc}, ctx)
         else:
-          a.sons[j] = semGenericStmt(c, a.sons[j], flags+{withinTypeDesc}, ctx)
-      a.sons[L-1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx)
+          a[j] = semGenericStmt(c, a[j], flags+{withinTypeDesc}, ctx)
+      a[^1] = semGenericStmtScope(c, a[^1], flags, ctx)
       closeScope(c)
 
   of nkVarSection, nkLetSection:
-    for i in 0 ..< len(n):
-      var a = n.sons[i]
+    for i in 0..<n.len:
+      var a = n[i]
       if a.kind == nkCommentStmt: continue
       if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a, c.config)
       checkMinSonsLen(a, 3, c.config)
-      var L = len(a)
-      a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
-      a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
-      for j in 0 .. L-3:
-        addTempDecl(c, getIdentNode(c, a.sons[j]), skVar)
+      a[^2] = semGenericStmt(c, a[^2], flags+{withinTypeDesc}, ctx)
+      a[^1] = semGenericStmt(c, a[^1], flags, ctx)
+      for j in 0..<a.len-2:
+        addTempDecl(c, getIdentNode(c, a[j]), skVar)
   of nkGenericParams:
-    for i in 0 ..< len(n):
-      var a = n.sons[i]
+    for i in 0..<n.len:
+      var a = n[i]
       if (a.kind != nkIdentDefs): illFormedAst(a, c.config)
       checkMinSonsLen(a, 3, c.config)
-      var L = len(a)
-      a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
+      a[^2] = semGenericStmt(c, a[^2], flags+{withinTypeDesc}, ctx)
       # do not perform symbol lookup for default expressions
-      for j in 0 .. L-3:
-        addTempDecl(c, getIdentNode(c, a.sons[j]), skType)
+      for j in 0..<a.len-2:
+        addTempDecl(c, getIdentNode(c, a[j]), skType)
   of nkConstSection:
-    for i in 0 ..< len(n):
-      var a = n.sons[i]
+    for i in 0..<n.len:
+      var a = n[i]
       if a.kind == nkCommentStmt: continue
       if (a.kind != nkConstDef): illFormedAst(a, c.config)
       checkSonsLen(a, 3, c.config)
-      addTempDecl(c, getIdentNode(c, a.sons[0]), skConst)
-      a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx)
-      a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx)
+      addTempDecl(c, getIdentNode(c, a[0]), skConst)
+      a[1] = semGenericStmt(c, a[1], flags+{withinTypeDesc}, ctx)
+      a[2] = semGenericStmt(c, a[2], flags, ctx)
   of nkTypeSection:
-    for i in 0 ..< len(n):
-      var a = n.sons[i]
+    for i in 0..<n.len:
+      var a = n[i]
       if a.kind == nkCommentStmt: continue
       if (a.kind != nkTypeDef): illFormedAst(a, c.config)
       checkSonsLen(a, 3, c.config)
-      addTempDecl(c, getIdentNode(c, a.sons[0]), skType)
-    for i in 0 ..< len(n):
-      var a = n.sons[i]
+      addTempDecl(c, getIdentNode(c, a[0]), skType)
+    for i in 0..<n.len:
+      var a = n[i]
       if a.kind == nkCommentStmt: continue
       if (a.kind != nkTypeDef): illFormedAst(a, c.config)
       checkSonsLen(a, 3, c.config)
-      if a.sons[1].kind != nkEmpty:
+      if a[1].kind != nkEmpty:
         openScope(c)
-        a.sons[1] = semGenericStmt(c, a.sons[1], flags, ctx)
-        a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, ctx)
+        a[1] = semGenericStmt(c, a[1], flags, ctx)
+        a[2] = semGenericStmt(c, a[2], flags+{withinTypeDesc}, ctx)
         closeScope(c)
       else:
-        a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, ctx)
+        a[2] = semGenericStmt(c, a[2], flags+{withinTypeDesc}, ctx)
   of nkEnumTy:
     if n.len > 0:
-      if n.sons[0].kind != nkEmpty:
-        n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
-      for i in 1 ..< len(n):
+      if n[0].kind != nkEmpty:
+        n[0] = semGenericStmt(c, n[0], flags+{withinTypeDesc}, ctx)
+      for i in 1..<n.len:
         var a: PNode
-        case n.sons[i].kind
-        of nkEnumFieldDef: a = n.sons[i].sons[0]
-        of nkIdent: a = n.sons[i]
+        case n[i].kind
+        of nkEnumFieldDef: a = n[i][0]
+        of nkIdent: a = n[i]
         else: illFormedAst(n, c.config)
         addDecl(c, newSymS(skUnknown, getIdentNode(c, a), c))
   of nkObjectTy, nkTupleTy, nkTupleClassTy:
     discard
   of nkFormalParams:
     checkMinSonsLen(n, 1, c.config)
-    if n.sons[0].kind != nkEmpty:
-      n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
-    for i in 1 ..< len(n):
-      var a = n.sons[i]
+    if n[0].kind != nkEmpty:
+      n[0] = semGenericStmt(c, n[0], flags+{withinTypeDesc}, ctx)
+    for i in 1..<n.len:
+      var a = n[i]
       if (a.kind != nkIdentDefs): illFormedAst(a, c.config)
       checkMinSonsLen(a, 3, c.config)
-      var L = len(a)
-      a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
-      a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
-      for j in 0 .. L-3:
-        addTempDecl(c, getIdentNode(c, a.sons[j]), skParam)
+      a[^2] = semGenericStmt(c, a[^2], flags+{withinTypeDesc}, ctx)
+      a[^1] = semGenericStmt(c, a[^1], flags, ctx)
+      for j in 0..<a.len-2:
+        addTempDecl(c, getIdentNode(c, a[j]), skParam)
   of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
      nkFuncDef, nkIteratorDef, nkLambdaKinds:
     checkSonsLen(n, bodyPos + 1, c.config)
-    if n.sons[namePos].kind != nkEmpty:
-      addTempDecl(c, getIdentNode(c, n.sons[0]), skProc)
+    if n[namePos].kind != nkEmpty:
+      addTempDecl(c, getIdentNode(c, n[0]), skProc)
     openScope(c)
-    n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos],
+    n[genericParamsPos] = semGenericStmt(c, n[genericParamsPos],
                                               flags, ctx)
-    if n.sons[paramsPos].kind != nkEmpty:
-      if n.sons[paramsPos].sons[0].kind != nkEmpty:
+    if n[paramsPos].kind != nkEmpty:
+      if n[paramsPos][0].kind != nkEmpty:
         addPrelimDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nil, n.info))
-      n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx)
-    n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, ctx)
+      n[paramsPos] = semGenericStmt(c, n[paramsPos], flags, ctx)
+    n[pragmasPos] = semGenericStmt(c, n[pragmasPos], flags, ctx)
     var body: PNode
-    if n.sons[namePos].kind == nkSym:
-      let s = n.sons[namePos].sym
+    if n[namePos].kind == nkSym:
+      let s = n[namePos].sym
       if sfGenSym in s.flags and s.ast == nil:
-        body = n.sons[bodyPos]
+        body = n[bodyPos]
       else:
         body = s.getBody
-    else: body = n.sons[bodyPos]
-    n.sons[bodyPos] = semGenericStmtScope(c, body, flags, ctx)
+    else: body = n[bodyPos]
+    n[bodyPos] = semGenericStmtScope(c, body, flags, ctx)
     closeScope(c)
   of nkPragma, nkPragmaExpr: discard
   of nkExprColonExpr, nkExprEqExpr:
     checkMinSonsLen(n, 2, c.config)
-    result.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
+    result[1] = semGenericStmt(c, n[1], flags, ctx)
   else:
-    for i in 0 ..< len(n):
-      result.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
+    for i in 0..<n.len:
+      result[i] = semGenericStmt(c, n[i], flags, ctx)
 
   when defined(nimsuggest):
     if withinTypeDesc in flags: dec c.inTypeContext
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index a45e1665a..605ddfafa 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -14,11 +14,11 @@ proc addObjFieldsToLocalScope(c: PContext; n: PNode) =
   template rec(n) = addObjFieldsToLocalScope(c, n)
   case n.kind
   of nkRecList:
-    for i in 0 ..< len(n):
+    for i in 0..<n.len:
       rec n[i]
   of nkRecCase:
-    if n.len > 0: rec n.sons[0]
-    for i in 1 ..< len(n):
+    if n.len > 0: rec n[0]
+    for i in 1..<n.len:
       if n[i].kind in {nkOfBranch, nkElse}: rec lastSon(n[i])
   of nkSym:
     let f = n.sym
@@ -47,8 +47,8 @@ proc rawHandleSelf(c: PContext; owner: PSym) =
         var t = c.p.selfSym.typ.skipTypes(abstractPtrs)
         while t.kind == tyObject:
           addObjFieldsToLocalScope(c, t.n)
-          if t.sons[0] == nil: break
-          t = t.sons[0].skipTypes(skipPtrs)
+          if t[0] == nil: break
+          t = t[0].skipTypes(skipPtrs)
 
 proc pushProcCon*(c: PContext; owner: PSym) =
   rawPushProcCon(c, owner)
@@ -123,24 +123,24 @@ proc freshGenSyms(n: PNode, owner, orig: PSym, symMap: var TIdTable) =
       idTablePut(symMap, s, x)
       n.sym = x
   else:
-    for i in 0 ..< safeLen(n): freshGenSyms(n.sons[i], owner, orig, symMap)
+    for i in 0..<n.safeLen: freshGenSyms(n[i], owner, orig, symMap)
 
 proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind)
 
 proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
-  if n.sons[bodyPos].kind != nkEmpty:
+  if n[bodyPos].kind != nkEmpty:
     let procParams = result.typ.n
-    for i in 1 ..< procParams.len:
+    for i in 1..<procParams.len:
       addDecl(c, procParams[i].sym)
     maybeAddResult(c, result, result.ast)
 
     inc c.inGenericInst
     # add it here, so that recursive generic procs are possible:
-    var b = n.sons[bodyPos]
+    var b = n[bodyPos]
     var symMap: TIdTable
     initIdTable symMap
     if params != nil:
-      for i in 1 ..< params.len:
+      for i in 1..<params.len:
         let param = params[i].sym
         if sfGenSym in param.flags:
           idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym)
@@ -152,7 +152,7 @@ proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
     dec c.inGenericInst
 
 proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
-  for i in 0 ..< c.generics.len:
+  for i in 0..<c.generics.len:
     if c.generics[i].genericSym.id == s.id:
       var oldPrc = c.generics[i].inst.sym
       pushProcCon(c, oldPrc)
@@ -160,7 +160,7 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
       pushInfoContext(c.config, oldPrc.info)
       openScope(c)
       var n = oldPrc.ast
-      n.sons[bodyPos] = copyTree(s.getBody)
+      n[bodyPos] = copyTree(s.getBody)
       instantiateBody(c, n, oldPrc.typ.n, oldPrc, s)
       closeScope(c)
       popInfoContext(c.config)
@@ -195,7 +195,7 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
   # perhaps the code can be extracted in a shared function.
   openScope(c)
   let genericTyp = header.base
-  for i in 0 .. (genericTyp.len - 2):
+  for i in 0..<genericTyp.len - 1:
     let genParam = genericTyp[i]
     var param: PSym
 
@@ -248,7 +248,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
   var result = instCopyType(cl, prc.typ)
   let originalParams = result.n
   result.n = originalParams.shallowCopy
-  for i in 1 ..< result.len:
+  for i in 1..<result.len:
     # twrong_field_caching requires these 'resetIdTable' calls:
     if i > 1:
       resetIdTable(cl.symMap)
@@ -280,7 +280,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
     if oldParam.ast != nil:
       var def = oldParam.ast.copyTree
       if def.kind == nkCall:
-        for i in 1 ..< def.len:
+        for i in 1..<def.len:
           def[i] = replaceTypeVarsN(cl, def[i])
 
       def = semExprWithType(c, def)
@@ -307,11 +307,11 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
   resetIdTable(cl.symMap)
   resetIdTable(cl.localCache)
   cl.isReturnType = true
-  result.sons[0] = replaceTypeVarsT(cl, result.sons[0])
+  result[0] = replaceTypeVarsT(cl, result[0])
   cl.isReturnType = false
-  result.n.sons[0] = originalParams[0].copyTree
-  if result.sons[0] != nil:
-    propagateToOwner(result, result.sons[0])
+  result.n[0] = originalParams[0].copyTree
+  if result[0] != nil:
+    propagateToOwner(result, result[0])
 
   eraseVoidParams(result)
   skipIntLiteralParams(result)
@@ -346,9 +346,9 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   pushOwner(c, result)
 
   openScope(c)
-  let gp = n.sons[genericParamsPos]
+  let gp = n[genericParamsPos]
   internalAssert c.config, gp.kind != nkEmpty
-  n.sons[namePos] = newSymNode(result)
+  n[namePos] = newSymNode(result)
   pushInfoContext(c.config, info, fn.detailedInfo)
   var entry = TInstantiation.new
   entry.sym = result
@@ -363,12 +363,12 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
     inc i
   rawPushProcCon(c, result)
   instantiateProcType(c, pt, result, info)
-  for j in 1 .. result.typ.len-1:
-    entry.concreteTypes[i] = result.typ.sons[j]
+  for j in 1..<result.typ.len:
+    entry.concreteTypes[i] = result.typ[j]
     inc i
   if tfTriggersCompileTime in result.typ.flags:
     incl(result.flags, sfCompileTime)
-  n.sons[genericParamsPos] = c.graph.emptyNode
+  n[genericParamsPos] = c.graph.emptyNode
   var oldPrc = genericCacheGet(fn, entry[], c.compilesContextId)
   if oldPrc == nil:
     # we MUST not add potentially wrong instantiations to the caching mechanism.
@@ -380,10 +380,10 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
     entry.compilesId = c.compilesContextId
     fn.procInstCache.add(entry)
     c.generics.add(makeInstPair(fn, entry))
-    if n.sons[pragmasPos].kind != nkEmpty:
-      pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
-    if isNil(n.sons[bodyPos]):
-      n.sons[bodyPos] = copyTree(fn.getBody)
+    if n[pragmasPos].kind != nkEmpty:
+      pragma(c, result, n[pragmasPos], allRoutinePragmas)
+    if isNil(n[bodyPos]):
+      n[bodyPos] = copyTree(fn.getBody)
     if c.inGenericContext == 0:
       instantiateBody(c, n, fn.typ.n, result, fn)
     sideEffectsCheck(c, result)
diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim
index 890a521f5..a8eb62067 100644
--- a/compiler/semmacrosanity.nim
+++ b/compiler/semmacrosanity.nim
@@ -16,17 +16,17 @@ proc ithField(n: PNode, field: var int): PSym =
   result = nil
   case n.kind
   of nkRecList:
-    for i in 0 ..< len(n):
-      result = ithField(n.sons[i], field)
+    for i in 0..<n.len:
+      result = ithField(n[i], field)
       if result != nil: return
   of nkRecCase:
-    if n.sons[0].kind != nkSym: return
-    result = ithField(n.sons[0], field)
+    if n[0].kind != nkSym: return
+    result = ithField(n[0], field)
     if result != nil: return
-    for i in 1 ..< len(n):
-      case n.sons[i].kind
+    for i in 1..<n.len:
+      case n[i].kind
       of nkOfBranch, nkElse:
-        result = ithField(lastSon(n.sons[i]), field)
+        result = ithField(lastSon(n[i]), field)
         if result != nil: return
       else: discard
   of nkSym:
@@ -35,12 +35,12 @@ proc ithField(n: PNode, field: var int): PSym =
   else: discard
 
 proc ithField(t: PType, field: var int): PSym =
-  var base = t.sons[0]
+  var base = t[0]
   while base != nil:
     let b = skipTypes(base, skipPtrs)
     result = ithField(b.n, field)
     if result != nil: return result
-    base = b.sons[0]
+    base = b[0]
   result = ithField(t.n, field)
 
 proc annotateType*(n: PNode, t: PType; conf: ConfigRef) =
@@ -51,20 +51,20 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef) =
   of nkObjConstr:
     let x = t.skipTypes(abstractPtrs)
     n.typ = t
-    for i in 1 ..< n.len:
+    for i in 1..<n.len:
       var j = i-1
       let field = x.ithField(j)
       if field.isNil:
         globalError conf, n.info, "invalid field at index " & $i
       else:
-        internalAssert(conf, n.sons[i].kind == nkExprColonExpr)
-        annotateType(n.sons[i].sons[1], field.typ, conf)
+        internalAssert(conf, n[i].kind == nkExprColonExpr)
+        annotateType(n[i][1], field.typ, conf)
   of nkPar, nkTupleConstr:
     if x.kind == tyTuple:
       n.typ = t
-      for i in 0 ..< n.len:
+      for i in 0..<n.len:
         if i >= x.len: globalError conf, n.info, "invalid field at index " & $i
-        else: annotateType(n.sons[i], x.sons[i], conf)
+        else: annotateType(n[i], x[i], conf)
     elif x.kind == tyProc and x.callConv == ccClosure:
       n.typ = t
     else:
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 27d398e1b..3e5c385e9 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -43,7 +43,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode
 proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode
 
 proc skipAddr(n: PNode): PNode {.inline.} =
-  (if n.kind == nkHiddenAddr: n.sons[0] else: n)
+  (if n.kind == nkHiddenAddr: n[0] else: n)
 
 proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
   result = newNodeI(nkBracketExpr, n.info)
@@ -51,7 +51,7 @@ proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
   result = semSubscript(c, result, flags)
   if result.isNil:
     let x = copyTree(n)
-    x.sons[0] = newIdentNode(getIdent(c.cache, "[]"), n.info)
+    x[0] = newIdentNode(getIdent(c.cache, "[]"), n.info)
     bracketNotFoundError(c, x)
     #localError(c.config, n.info, "could not resolve: " & $n)
     result = n
@@ -60,16 +60,16 @@ proc semArrPut(c: PContext; n: PNode; flags: TExprFlags): PNode =
   # rewrite `[]=`(a, i, x)  back to ``a[i] = x``.
   let b = newNodeI(nkBracketExpr, n.info)
   b.add(n[1].skipAddr)
-  for i in 2..n.len-2: b.add(n[i])
+  for i in 2..<n.len-1: b.add(n[i])
   result = newNodeI(nkAsgn, n.info, 2)
-  result.sons[0] = b
-  result.sons[1] = n.lastSon
+  result[0] = b
+  result[1] = n.lastSon
   result = semAsgn(c, result, noOverloadedSubscript)
 
 proc semAsgnOpr(c: PContext; n: PNode): PNode =
   result = newNodeI(nkAsgn, n.info, 2)
-  result.sons[0] = n[1]
-  result.sons[1] = n[2]
+  result[0] = n[1]
+  result[1] = n[2]
   result = semAsgn(c, result, noOverloadedAsgn)
 
 proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode =
@@ -84,8 +84,8 @@ proc expectIntLit(c: PContext, n: PNode): int =
 
 proc semInstantiationInfo(c: PContext, n: PNode): PNode =
   result = newNodeIT(nkTupleConstr, n.info, n.typ)
-  let idx = expectIntLit(c, n.sons[1])
-  let useFullPaths = expectIntLit(c, n.sons[2])
+  let idx = expectIntLit(c, n[1])
+  let useFullPaths = expectIntLit(c, n[2])
   let info = getInfoContext(c.config, idx)
   var filename = newNodeIT(nkStrLit, n.info, getSysType(c.graph, n.info, tyString))
   filename.strVal = if useFullPaths != 0: toFullPath(c.config, info) else: toFilename(c.config, info)
@@ -118,7 +118,7 @@ proc uninstantiate(t: PType): PType =
   result = case t.kind
     of tyMagicGenerics: t
     of tyUserDefinedGenerics: t.base
-    of tyCompositeTypeClass: uninstantiate t.sons[1]
+    of tyCompositeTypeClass: uninstantiate t[1]
     else: t
 
 proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym): PNode =
@@ -128,7 +128,7 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
   var operand = operand.skipTypes(skippedTypes)
 
   template operand2: PType =
-    traitCall.sons[2].typ.skipTypes({tyTypeDesc})
+    traitCall[2].typ.skipTypes({tyTypeDesc})
 
   template typeWithSonsResult(kind, sons): PNode =
     newTypeWithSons(context, kind, sons).toNode(traitCall.info)
@@ -143,8 +143,8 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
     return typeWithSonsResult(tyNot, @[operand])
   of "typeToString":
     var prefer = preferTypeName
-    if traitCall.sons.len >= 2:
-      let preferStr = traitCall.sons[2].strVal
+    if traitCall.len >= 2:
+      let preferStr = traitCall[2].strVal
       prefer = parseEnum[TPreferedDesc](preferStr)
     result = newStrNode(nkStrLit, operand.typeToString(prefer))
     result.typ = newType(tyString, context)
@@ -178,7 +178,7 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
 
 proc semTypeTraits(c: PContext, n: PNode): PNode =
   checkMinSonsLen(n, 2, c.config)
-  let t = n.sons[1].typ
+  let t = n[1].typ
   internalAssert c.config, t != nil and t.kind == tyTypeDesc
   if t.len > 0:
     # This is either a type known to sem or a typedesc
@@ -190,7 +190,7 @@ proc semTypeTraits(c: PContext, n: PNode): PNode =
 
 proc semOrd(c: PContext, n: PNode): PNode =
   result = n
-  let parType = n.sons[1].typ
+  let parType = n[1].typ
   if isOrdinalType(parType, allowEnumWithHoles=true):
     discard
   elif parType.kind == tySet:
@@ -203,17 +203,17 @@ proc semOrd(c: PContext, n: PNode): PNode =
 
 proc semBindSym(c: PContext, n: PNode): PNode =
   result = copyNode(n)
-  result.add(n.sons[0])
+  result.add(n[0])
 
-  let sl = semConstExpr(c, n.sons[1])
+  let sl = semConstExpr(c, n[1])
   if sl.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
-    localError(c.config, n.sons[1].info, errStringLiteralExpected)
+    localError(c.config, n[1].info, errStringLiteralExpected)
     return errorNode(c, n)
 
-  let isMixin = semConstExpr(c, n.sons[2])
+  let isMixin = semConstExpr(c, n[2])
   if isMixin.kind != nkIntLit or isMixin.intVal < 0 or
       isMixin.intVal > high(TSymChoiceRule).int:
-    localError(c.config, n.sons[2].info, errConstExprExpected)
+    localError(c.config, n[2].info, errConstExprExpected)
     return errorNode(c, n)
 
   let id = newIdentNode(getIdent(c.cache, sl.strVal), n.info)
@@ -227,7 +227,7 @@ proc semBindSym(c: PContext, n: PNode): PNode =
       return sc
     result.add(sc)
   else:
-    errorUndeclaredIdentifier(c, n.sons[1].info, sl.strVal)
+    errorUndeclaredIdentifier(c, n[1].info, sl.strVal)
 
 proc opBindSym(c: PContext, scope: PScope, n: PNode, isMixin: int, info: PNode): PNode =
   if n.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit, nkIdent}:
@@ -293,15 +293,15 @@ proc semDynamicBindSym(c: PContext, n: PNode): PNode =
 proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode
 
 proc semOf(c: PContext, n: PNode): PNode =
-  if len(n) == 3:
-    n.sons[1] = semExprWithType(c, n.sons[1])
-    n.sons[2] = semExprWithType(c, n.sons[2], {efDetermineType})
-    #restoreOldStyleType(n.sons[1])
-    #restoreOldStyleType(n.sons[2])
-    let a = skipTypes(n.sons[1].typ, abstractPtrs)
-    let b = skipTypes(n.sons[2].typ, abstractPtrs)
-    let x = skipTypes(n.sons[1].typ, abstractPtrs-{tyTypeDesc})
-    let y = skipTypes(n.sons[2].typ, abstractPtrs-{tyTypeDesc})
+  if n.len == 3:
+    n[1] = semExprWithType(c, n[1])
+    n[2] = semExprWithType(c, n[2], {efDetermineType})
+    #restoreOldStyleType(n[1])
+    #restoreOldStyleType(n[2])
+    let a = skipTypes(n[1].typ, abstractPtrs)
+    let b = skipTypes(n[2].typ, abstractPtrs)
+    let x = skipTypes(n[1].typ, abstractPtrs-{tyTypeDesc})
+    let y = skipTypes(n[2].typ, abstractPtrs-{tyTypeDesc})
 
     if x.kind == tyTypeDesc or y.kind != tyTypeDesc:
       localError(c.config, n.info, "'of' takes object types")
@@ -349,14 +349,13 @@ proc semUnown(c: PContext; n: PNode): PNode =
         for e in elems: result.rawAddSon(e)
       else:
         result = t
-    of tyOwned: result = t.sons[0]
+    of tyOwned: result = t[0]
     of tySequence, tyOpenArray, tyArray, tyVarargs, tyVar, tyLent,
        tyGenericInst, tyAlias:
-      let L = t.len-1
-      let b = unownedType(c, t[L])
-      if b != t[L]:
+      let b = unownedType(c, t[^1])
+      if b != t[^1]:
         result = copyType(t, t.owner, keepId = false)
-        result[L] = b
+        result[^1] = b
         result.flags.excl tfHasOwned
       else:
         result = t
@@ -366,7 +365,7 @@ proc semUnown(c: PContext; n: PNode): PNode =
   result = copyTree(n[1])
   result.typ = unownedType(c, result.typ)
   # little hack for injectdestructors.nim (see bug #11350):
-  #result.sons[0].typ = nil
+  #result[0].typ = nil
 
 proc magicsAfterOverloadResolution(c: PContext, n: PNode,
                                    flags: TExprFlags): PNode =
@@ -437,7 +436,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
     result = n
     let t = n[1].typ.skipTypes(abstractVar)
     if t.destructor != nil:
-      result.sons[0] = newSymNode(t.destructor)
+      result[0] = newSymNode(t.destructor)
   of mUnown:
     result = semUnown(c, n)
   else: result = n
diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim
index eff7bd825..0062af24b 100644
--- a/compiler/semobjconstr.nim
+++ b/compiler/semobjconstr.nim
@@ -48,7 +48,7 @@ proc invalidObjConstr(c: PContext, n: PNode) =
 proc locateFieldInInitExpr(c: PContext, field: PSym, initExpr: PNode): PNode =
   # Returns the assignment nkExprColonExpr node or nil
   let fieldId = field.name.id
-  for i in 1 ..< initExpr.len:
+  for i in 1..<initExpr.len:
     let assignment = initExpr[i]
     if assignment.kind != nkExprColonExpr:
       invalidObjConstr(c, assignment)
@@ -70,13 +70,13 @@ proc semConstrField(c: PContext, flags: TExprFlags,
     var initValue = semExprFlagDispatched(c, assignment[1], flags)
     if initValue != nil:
       initValue = fitNode(c, field.typ, initValue, assignment.info)
-    assignment.sons[0] = newSymNode(field)
-    assignment.sons[1] = initValue
+    assignment[0] = newSymNode(field)
+    assignment[1] = initValue
     assignment.flags.incl nfSem
     return initValue
 
 proc caseBranchMatchesExpr(branch, matched: PNode): bool =
-  for i in 0 .. branch.len-2:
+  for i in 0..<branch.len-1:
     if branch[i].kind == nkRange:
       if overlap(branch[i], matched): return true
     elif exprStructuralEquivalent(branch[i], matched):
@@ -86,11 +86,11 @@ proc caseBranchMatchesExpr(branch, matched: PNode): bool =
 
 template processBranchVals(b, op) =
   if b.kind != nkElifBranch:
-    for i in 0 .. b.len-2:
+    for i in 0..<b.len-1:
       if b[i].kind == nkIntLit:
         result.op(b[i].intVal.int)
       elif b[i].kind == nkRange:
-        for i in b[i][0].intVal .. b[i][1].intVal:
+        for i in b[i][0].intVal..b[i][1].intVal:
           result.op(i.int)
 
 proc allPossibleValues(c: PContext, t: PType): IntSet =
@@ -100,7 +100,7 @@ proc allPossibleValues(c: PContext, t: PType): IntSet =
     for field in t.n.sons:
       result.incl(field.sym.position)
   else:
-    for i in toInt64(firstOrd(c.config, t)) .. toInt64(lastOrd(c.config, t)):
+    for i in toInt64(firstOrd(c.config, t))..toInt64(lastOrd(c.config, t)):
       result.incl(i.int)
 
 proc branchVals(c: PContext, caseNode: PNode, caseIdx: int,
@@ -109,15 +109,15 @@ proc branchVals(c: PContext, caseNode: PNode, caseIdx: int,
     result = initIntSet()
     processBranchVals(caseNode[caseIdx], incl)
   else:
-    result = allPossibleValues(c, caseNode.sons[0].typ)
-    for i in 1 .. caseNode.len-2:
+    result = allPossibleValues(c, caseNode[0].typ)
+    for i in 1..<caseNode.len-1:
       processBranchVals(caseNode[i], excl)
 
 proc rangeTypVals(rangeTyp: PType): IntSet =
   assert rangeTyp.kind == tyRange
-  let (a, b) = (rangeTyp.n.sons[0].intVal, rangeTyp.n.sons[1].intVal)
+  let (a, b) = (rangeTyp.n[0].intVal, rangeTyp.n[1].intVal)
   result = initIntSet()
-  for it in a .. b:
+  for it in a..b:
     result.incl(it.int)
 
 proc formatUnsafeBranchVals(t: PType, diffVals: IntSet): string =
@@ -127,8 +127,8 @@ proc formatUnsafeBranchVals(t: PType, diffVals: IntSet): string =
     if t.kind in {tyEnum, tyBool}:
       var i = 0
       for val in diffVals:
-        while t.n.sons[i].sym.position < val: inc(i)
-        strs.add(t.n.sons[i].sym.name.s)
+        while t.n[i].sym.position < val: inc(i)
+        strs.add(t.n[i].sym.name.s)
     else:
       for val in diffVals:
         strs.add($val)
@@ -145,7 +145,7 @@ proc findUsefulCaseContext(c: PContext, discrimator: PNode): (PNode, int) =
 proc pickCaseBranch(caseExpr, matched: PNode): PNode =
   # XXX: Perhaps this proc already exists somewhere
   let endsWithElse = caseExpr[^1].kind == nkElse
-  for i in 1 .. caseExpr.len - 1 - int(endsWithElse):
+  for i in 1..<caseExpr.len - int(endsWithElse):
     if caseExpr[i].caseBranchMatchesExpr(matched):
       return caseExpr[i]
 
@@ -203,19 +203,19 @@ proc semConstructFields(c: PContext, recNode: PNode,
   of nkRecCase:
     template fieldsPresentInBranch(branchIdx: int): string =
       let branch = recNode[branchIdx]
-      let fields = branch[branch.len - 1]
+      let fields = branch[^1]
       fieldsPresentInInitExpr(c, fields, initExpr)
 
     template checkMissingFields(branchNode: PNode) =
       if branchNode != nil:
-        let fields = branchNode[branchNode.len - 1]
+        let fields = branchNode[^1]
         checkForMissingFields(c, fields, initExpr)
 
-    let discriminator = recNode.sons[0]
+    let discriminator = recNode[0]
     internalAssert c.config, discriminator.kind == nkSym
     var selectedBranch = -1
 
-    for i in 1 ..< recNode.len:
+    for i in 1..<recNode.len:
       let innerRecords = recNode[i][^1]
       let status = semConstructFields(c, innerRecords, initExpr, flags)
       if status notin {initNone, initUnknown}:
@@ -252,7 +252,7 @@ proc semConstructFields(c: PContext, recNode: PNode,
         localError(c.config, discriminatorVal.info, ("possible values " &
           "$2are in conflict with discriminator values for " &
           "selected object branch $1.") % [$selectedBranch,
-          formatUnsafeBranchVals(recNode.sons[0].typ, valsDiff)])
+          formatUnsafeBranchVals(recNode[0].typ, valsDiff)])
 
       let branchNode = recNode[selectedBranch]
       let flags = flags*{efAllowDestructor} + {efPreferStatic,
@@ -264,7 +264,7 @@ proc semConstructFields(c: PContext, recNode: PNode,
         if discriminatorVal.kind notin nkLiterals and (
             not isOrdinalType(discriminatorVal.typ, true) or
             lengthOrd(c.config, discriminatorVal.typ) > MaxSetElements or
-            lengthOrd(c.config, recNode.sons[0].typ) > MaxSetElements):
+            lengthOrd(c.config, recNode[0].typ) > MaxSetElements):
           localError(c.config, discriminatorVal.info,
             "branch initialization with a runtime discriminator only " &
             "supports ordinal types with 2^16 elements or less.")
@@ -305,7 +305,7 @@ proc semConstructFields(c: PContext, recNode: PNode,
             failedBranch = selectedBranch
         else:
           # With an else clause, check that all other branches don't match:
-          for i in 1 .. (recNode.len - 2):
+          for i in 1..<recNode.len - 1:
             if recNode[i].caseBranchMatchesExpr(discriminatorVal):
               failedBranch = i
               break
@@ -345,7 +345,7 @@ proc semConstructFields(c: PContext, recNode: PNode,
         else:
           # All bets are off. If any of the branches has a mandatory
           # fields we must produce an error:
-          for i in 1 ..< recNode.len: checkMissingFields recNode[i]
+          for i in 1..<recNode.len: checkMissingFields recNode[i]
 
   of nkSym:
     let field = recNode.sym
@@ -364,12 +364,12 @@ proc semConstructType(c: PContext, initExpr: PNode,
     mergeInitStatus(result, status)
     if status in {initPartial, initNone, initUnknown}:
       checkForMissingFields c, t.n, initExpr
-    let base = t.sons[0]
+    let base = t[0]
     if base == nil: break
     t = skipTypes(base, skipPtrs)
 
 proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
-  var t = semTypeNode(c, n.sons[0], nil)
+  var t = semTypeNode(c, n[0], nil)
   result = newNodeIT(nkObjConstr, n.info, t)
   for child in n: result.add child
 
@@ -379,7 +379,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
 
   t = skipTypes(t, {tyGenericInst, tyAlias, tySink, tyOwned})
   if t.kind == tyRef:
-    t = skipTypes(t.sons[0], {tyGenericInst, tyAlias, tySink, tyOwned})
+    t = skipTypes(t[0], {tyGenericInst, tyAlias, tySink, tyOwned})
     if optOwnedRefs in c.config.globalOptions:
       result.typ = makeVarType(c, result.typ, tyOwned)
       # we have to watch out, there are also 'owned proc' types that can be used
@@ -418,7 +418,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
       let id = considerQuotedIdent(c, field[0])
       # This node was not processed. There are two possible reasons:
       # 1) It was shadowed by a field with the same name on the left
-      for j in 1 ..< i:
+      for j in 1..<i:
         let prevId = considerQuotedIdent(c, result[j][0])
         if prevId.id == id.id:
           localError(c.config, field.info, errFieldInitTwice % id.s)
diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim
index 724c868b7..62264ab40 100644
--- a/compiler/semparallel.nim
+++ b/compiler/semparallel.nim
@@ -92,10 +92,9 @@ proc lookupSlot(c: AnalysisCtx; s: PSym): int =
 proc getSlot(c: var AnalysisCtx; v: PSym): ptr MonotonicVar =
   let s = lookupSlot(c, v)
   if s >= 0: return addr(c.locals[s])
-  let L = c.locals.len
-  c.locals.setLen(L+1)
-  c.locals[L].v = v
-  return addr(c.locals[L])
+  c.locals.setLen(c.locals.len+1)
+  c.locals[^1].v = v
+  return addr(c.locals[^1])
 
 proc gatherArgs(c: var AnalysisCtx; n: PNode) =
   for i in 0..<n.safeLen:
@@ -123,7 +122,7 @@ proc checkLocal(c: AnalysisCtx; n: PNode) =
     if s >= 0 and c.locals[s].stride != nil:
       localError(c.graph.config, n.info, "invalid usage of counter after increment")
   else:
-    for i in 0 ..< n.safeLen: checkLocal(c, n.sons[i])
+    for i in 0..<n.safeLen: checkLocal(c, n[i])
 
 template `?`(x): untyped = x.renderTree
 
@@ -184,7 +183,7 @@ proc stride(c: AnalysisCtx; n: PNode): BiggestInt =
     if s >= 0 and c.locals[s].stride != nil:
       result = c.locals[s].stride.intVal
   else:
-    for i in 0 ..< n.safeLen: result += stride(c, n.sons[i])
+    for i in 0..<n.safeLen: result += stride(c, n[i])
 
 proc subStride(c: AnalysisCtx; n: PNode): PNode =
   # substitute with stride:
@@ -196,7 +195,7 @@ proc subStride(c: AnalysisCtx; n: PNode): PNode =
       result = n
   elif n.safeLen > 0:
     result = shallowCopy(n)
-    for i in 0 ..< n.len: result.sons[i] = subStride(c, n.sons[i])
+    for i in 0..<n.len: result[i] = subStride(c, n[i])
   else:
     result = n
 
@@ -216,8 +215,8 @@ proc checkSlicesAreDisjoint(c: var AnalysisCtx) =
   #
   # Or even worse:
   #   while true:
-  #     spawn f(a[i+1 .. i+3])
-  #     spawn f(a[i+4 .. i+5])
+  #     spawn f(a[i+1..i+3])
+  #     spawn f(a[i+4..i+5])
   #     inc i, 4
   # Prove that i*k*stride + 3 != i*k'*stride + 5
   # For the correct example this amounts to
@@ -226,15 +225,15 @@ proc checkSlicesAreDisjoint(c: var AnalysisCtx) =
   # For now, we don't try to prove things like that at all, even though it'd
   # be feasible for many useful examples. Instead we attach the slice to
   # a spawn and if the attached spawns differ, we bail out:
-  for i in 0 .. high(c.slices):
-    for j in i+1 .. high(c.slices):
+  for i in 0..high(c.slices):
+    for j in i+1..high(c.slices):
       let x = c.slices[i]
       let y = c.slices[j]
       if x.spawnId != y.spawnId and guards.sameTree(x.x, y.x):
         if not x.inLoop or not y.inLoop:
           # XXX strictly speaking, 'or' is not correct here and it needs to
           # be 'and'. However this prevents too many obviously correct programs
-          # like f(a[0..x]); for i in x+1 .. a.high: f(a[i])
+          # like f(a[0..x]); for i in x+1..a.high: f(a[i])
           overlap(c.guards, c.graph.config, x.a, x.b, y.a, y.b)
         elif (let k = simpleSlice(x.a, x.b); let m = simpleSlice(y.a, y.b);
               k >= 0 and m >= 0):
@@ -255,7 +254,7 @@ proc checkSlicesAreDisjoint(c: var AnalysisCtx) =
 proc analyse(c: var AnalysisCtx; n: PNode)
 
 proc analyseSons(c: var AnalysisCtx; n: PNode) =
-  for i in 0 ..< safeLen(n): analyse(c, n[i])
+  for i in 0..<n.safeLen: analyse(c, n[i])
 
 proc min(a, b: PNode): PNode =
   if a.isNil: result = b
@@ -295,31 +294,31 @@ proc analyseCall(c: var AnalysisCtx; n: PNode; op: PSym) =
     analyseSons(c, n)
 
 proc analyseCase(c: var AnalysisCtx; n: PNode) =
-  analyse(c, n.sons[0])
+  analyse(c, n[0])
   let oldFacts = c.guards.s.len
   for i in 1..<n.len:
-    let branch = n.sons[i]
+    let branch = n[i]
     setLen(c.guards.s, oldFacts)
     addCaseBranchFacts(c.guards, n, i)
-    for i in 0 ..< branch.len:
-      analyse(c, branch.sons[i])
+    for i in 0..<branch.len:
+      analyse(c, branch[i])
   setLen(c.guards.s, oldFacts)
 
 proc analyseIf(c: var AnalysisCtx; n: PNode) =
-  analyse(c, n.sons[0].sons[0])
+  analyse(c, n[0][0])
   let oldFacts = c.guards.s.len
-  addFact(c.guards, canon(n.sons[0].sons[0], c.guards.o))
+  addFact(c.guards, canon(n[0][0], c.guards.o))
 
-  analyse(c, n.sons[0].sons[1])
+  analyse(c, n[0][1])
   for i in 1..<n.len:
-    let branch = n.sons[i]
+    let branch = n[i]
     setLen(c.guards.s, oldFacts)
     for j in 0..i-1:
-      addFactNeg(c.guards, canon(n.sons[j].sons[0], c.guards.o))
+      addFactNeg(c.guards, canon(n[j][0], c.guards.o))
     if branch.len > 1:
-      addFact(c.guards, canon(branch.sons[0], c.guards.o))
-    for i in 0 ..< branch.len:
-      analyse(c, branch.sons[i])
+      addFact(c.guards, canon(branch[0], c.guards.o))
+    for i in 0..<branch.len:
+      analyse(c, branch[i])
   setLen(c.guards.s, oldFacts)
 
 proc analyse(c: var AnalysisCtx; n: PNode) =
@@ -365,7 +364,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
           gatherArgs(c, value[1])
           analyseSons(c, value[1])
       if value.kind != nkEmpty:
-        for j in 0 .. it.len-3:
+        for j in 0..<it.len-2:
           if it[j].isLocal:
             let slot = c.getSlot(it[j].sym)
             if slot.lower.isNil: slot.lower = value
@@ -374,22 +373,22 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
   of nkCaseStmt: analyseCase(c, n)
   of nkWhen, nkIfStmt, nkIfExpr: analyseIf(c, n)
   of nkWhileStmt:
-    analyse(c, n.sons[0])
+    analyse(c, n[0])
     # 'while true' loop?
     inc c.inLoop
-    if isTrue(n.sons[0]):
-      analyseSons(c, n.sons[1])
+    if isTrue(n[0]):
+      analyseSons(c, n[1])
     else:
       # loop may never execute:
       let oldState = c.locals.len
       let oldFacts = c.guards.s.len
-      addFact(c.guards, canon(n.sons[0], c.guards.o))
-      analyse(c, n.sons[1])
+      addFact(c.guards, canon(n[0], c.guards.o))
+      analyse(c, n[1])
       setLen(c.locals, oldState)
       setLen(c.guards.s, oldFacts)
       # we know after the loop the negation holds:
-      if not hasSubnodeWith(n.sons[1], nkBreakStmt):
-        addFactNeg(c.guards, canon(n.sons[0], c.guards.o))
+      if not hasSubnodeWith(n[1], nkBreakStmt):
+        addFactNeg(c.guards, canon(n[0], c.guards.o))
     dec c.inLoop
   of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
       nkMacroDef, nkTemplateDef, nkConstSection, nkPragma, nkFuncDef:
@@ -412,16 +411,16 @@ proc transformSlices(g: ModuleGraph; n: PNode): PNode =
       return result
   if n.safeLen > 0:
     result = shallowCopy(n)
-    for i in 0 ..< n.len:
-      result.sons[i] = transformSlices(g, n.sons[i])
+    for i in 0..<n.len:
+      result[i] = transformSlices(g, n[i])
   else:
     result = n
 
 proc transformSpawn(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode
 proc transformSpawnSons(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode =
   result = shallowCopy(n)
-  for i in 0 ..< n.len:
-    result.sons[i] = transformSpawn(g, owner, n.sons[i], barrier)
+  for i in 0..<n.len:
+    result[i] = transformSpawn(g, owner, n[i], barrier)
 
 proc transformSpawn(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode =
   case n.kind
@@ -435,16 +434,16 @@ proc transformSpawn(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode =
         if result.isNil:
           result = newNodeI(nkStmtList, n.info)
           result.add n
-        let t = b[1][0].typ.sons[0]
+        let t = b[1][0].typ[0]
         if spawnResult(t, true) == srByVar:
           result.add wrapProcForSpawn(g, owner, m, b.typ, barrier, it[0])
-          it.sons[it.len-1] = newNodeI(nkEmpty, it.info)
+          it[^1] = newNodeI(nkEmpty, it.info)
         else:
-          it.sons[it.len-1] = wrapProcForSpawn(g, owner, m, b.typ, barrier, nil)
+          it[^1] = wrapProcForSpawn(g, owner, m, b.typ, barrier, nil)
     if result.isNil: result = n
   of nkAsgn, nkFastAsgn:
     let b = n[1]
-    if getMagic(b) == mSpawn and (let t = b[1][0].typ.sons[0];
+    if getMagic(b) == mSpawn and (let t = b[1][0].typ[0];
         spawnResult(t, true) == srByVar):
       let m = transformSlices(g, b)
       return wrapProcForSpawn(g, owner, m, b.typ, barrier, n[0])
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index 36179511c..e64bccdce 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -91,7 +91,7 @@ proc isLocalVar(a: PEffects, s: PSym): bool =
 proc getLockLevel(t: PType): TLockLevel =
   var t = t
   # tyGenericInst(TLock {tyGenericBody}, tyStatic, tyObject):
-  if t.kind == tyGenericInst and t.len == 3: t = t.sons[1]
+  if t.kind == tyGenericInst and t.len == 3: t = t[1]
   if t.kind == tyStatic and t.n != nil and t.n.kind in {nkCharLit..nkInt64Lit}:
     result = t.n.intVal.TLockLevel
 
@@ -131,21 +131,21 @@ proc guardGlobal(a: PEffects; n: PNode; guard: PSym) =
 # 'guard*' are checks which are concerned with 'guard' annotations
 # (var x{.guard: y.}: int)
 proc guardDotAccess(a: PEffects; n: PNode) =
-  let ri = n.sons[1]
+  let ri = n[1]
   if ri.kind != nkSym or ri.sym.kind != skField: return
   var g = ri.sym.guard
   if g.isNil or a.isTopLevel: return
   # fixup guard:
   if g.kind == skUnknown:
     var field: PSym = nil
-    var ty = n.sons[0].typ.skipTypes(abstractPtrs)
+    var ty = n[0].typ.skipTypes(abstractPtrs)
     if ty.kind == tyTuple and not ty.n.isNil:
       field = lookupInRecord(ty.n, g.name)
     else:
       while ty != nil and ty.kind == tyObject:
         field = lookupInRecord(ty.n, g.name)
         if field != nil: break
-        ty = ty.sons[0]
+        ty = ty[0]
         if ty == nil: break
         ty = ty.skipTypes(skipPtrs)
     if field == nil:
@@ -156,8 +156,8 @@ proc guardDotAccess(a: PEffects; n: PNode) =
     # XXX unfortunately this is not correct for generic instantiations!
   if g.kind == skField:
     let dot = newNodeI(nkDotExpr, n.info, 2)
-    dot.sons[0] = n.sons[0]
-    dot.sons[1] = newSymNode(g)
+    dot[0] = n[0]
+    dot[1] = newSymNode(g)
     dot.typ = g.typ
     for L in a.locked:
       #if a.guards.sameSubexprs(dot, L): return
@@ -305,7 +305,7 @@ proc createTag(g: ModuleGraph; n: PNode): PNode =
 proc addEffect(a: PEffects, e: PNode, useLineInfo=true) =
   assert e.kind != nkRaiseStmt
   var aa = a.exc
-  for i in a.bottom ..< aa.len:
+  for i in a.bottom..<aa.len:
     if sameType(a.graph.excType(aa[i]), a.graph.excType(e)):
       if not useLineInfo or a.config.cmd == cmdDoc: return
       elif aa[i].info == e.info: return
@@ -313,7 +313,7 @@ proc addEffect(a: PEffects, e: PNode, useLineInfo=true) =
 
 proc addTag(a: PEffects, e: PNode, useLineInfo=true) =
   var aa = a.tags
-  for i in 0 ..< aa.len:
+  for i in 0..<aa.len:
     if sameType(aa[i].typ.skipTypes(skipPtrs), e.typ.skipTypes(skipPtrs)):
       if not useLineInfo or a.config.cmd == cmdDoc: return
       elif aa[i].info == e.info: return
@@ -344,7 +344,7 @@ proc catches(tracked: PEffects, e: PType) =
   while i < L:
     # r supertype of e?
     if safeInheritanceDiff(tracked.graph.excType(tracked.exc[i]), e) <= 0:
-      tracked.exc.sons[i] = tracked.exc.sons[L-1]
+      tracked.exc[i] = tracked.exc[L-1]
       dec L
     else:
       inc i
@@ -366,7 +366,7 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
   var inter: TIntersection = @[]
 
   inc tracked.inTryStmt
-  track(tracked, n.sons[0])
+  track(tracked, n[0])
   dec tracked.inTryStmt
   for i in oldState..<tracked.init.len:
     addToIntersection(inter, tracked.init[i])
@@ -375,35 +375,33 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
   var hasFinally = false
 
   # Collect the exceptions caught by the except branches
-  for i in 1 ..< n.len:
-    let b = n.sons[i]
-    let blen = len(b)
+  for i in 1..<n.len:
+    let b = n[i]
     if b.kind == nkExceptBranch:
       inc branches
-      if blen == 1:
+      if b.len == 1:
         catchesAll(tracked)
       else:
-        for j in 0 .. blen - 2:
-          if b.sons[j].isInfixAs():
-            assert(b.sons[j][1].kind == nkType)
-            catches(tracked, b.sons[j][1].typ)
+        for j in 0..<b.len - 1:
+          if b[j].isInfixAs():
+            assert(b[j][1].kind == nkType)
+            catches(tracked, b[j][1].typ)
           else:
-            assert(b.sons[j].kind == nkType)
-            catches(tracked, b.sons[j].typ)
+            assert(b[j].kind == nkType)
+            catches(tracked, b[j].typ)
     else:
       assert b.kind == nkFinally
   # Add any other exception raised in the except bodies
-  for i in 1 ..< n.len:
-    let b = n.sons[i]
-    let blen = len(b)
+  for i in 1..<n.len:
+    let b = n[i]
     if b.kind == nkExceptBranch:
       setLen(tracked.init, oldState)
-      track(tracked, b.sons[blen-1])
+      track(tracked, b[^1])
       for i in oldState..<tracked.init.len:
         addToIntersection(inter, tracked.init[i])
     else:
       setLen(tracked.init, oldState)
-      track(tracked, b.sons[blen-1])
+      track(tracked, b[^1])
       hasFinally = true
 
   tracked.bottom = oldBottom
@@ -427,8 +425,8 @@ proc isForwardedProc(n: PNode): bool =
   result = n.kind == nkSym and sfForward in n.sym.flags
 
 proc trackPragmaStmt(tracked: PEffects, n: PNode) =
-  for i in 0 ..< len(n):
-    var it = n.sons[i]
+  for i in 0..<n.len:
+    var it = n[i]
     if whichPragma(it) == wEffects:
       # list the computed effects up to here:
       listEffects(tracked)
@@ -459,7 +457,7 @@ proc mergeLockLevels(tracked: PEffects, n: PNode, lockLevel: TLockLevel) =
     tracked.maxLockLevel = max(tracked.maxLockLevel, lockLevel)
 
 proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
-  let pragma = s.ast.sons[pragmasPos]
+  let pragma = s.ast[pragmasPos]
   let spec = effectSpec(pragma, wRaises)
   mergeEffects(tracked, spec, n)
 
@@ -531,8 +529,8 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType; caller: PNode)
   let op = a.typ
   # assume indirect calls are taken here:
   if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit and not isTrival(caller):
-    internalAssert tracked.config, op.n.sons[0].kind == nkEffectList
-    var effectList = op.n.sons[0]
+    internalAssert tracked.config, op.n[0].kind == nkEffectList
+    var effectList = op.n[0]
     var s = n.skipConv
     if s.kind == nkCast and s[1].typ.kind == tyProc:
       s = s[1]
@@ -553,8 +551,8 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType; caller: PNode)
       elif tfNoSideEffect notin op.flags and not isOwnedProcVar(a, tracked.owner):
         markSideEffect(tracked, a)
     else:
-      mergeEffects(tracked, effectList.sons[exceptionEffects], n)
-      mergeTags(tracked, effectList.sons[tagEffects], n)
+      mergeEffects(tracked, effectList[exceptionEffects], n)
+      mergeTags(tracked, effectList[tagEffects], n)
       if notGcSafe(op):
         if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
         markGcUnsafe(tracked, a)
@@ -582,23 +580,23 @@ proc breaksBlock(n: PNode): bool =
     it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
 
 proc trackCase(tracked: PEffects, n: PNode) =
-  track(tracked, n.sons[0])
+  track(tracked, n[0])
   let oldState = tracked.init.len
   let oldFacts = tracked.guards.s.len
-  let stringCase = skipTypes(n.sons[0].typ,
+  let stringCase = skipTypes(n[0].typ,
         abstractVarRange-{tyTypeDesc}).kind in {tyFloat..tyFloat128, tyString}
-  let interesting = not stringCase and interestingCaseExpr(n.sons[0]) and
+  let interesting = not stringCase and interestingCaseExpr(n[0]) and
         warnProveField in tracked.config.notes
   var inter: TIntersection = @[]
   var toCover = 0
   for i in 1..<n.len:
-    let branch = n.sons[i]
+    let branch = n[i]
     setLen(tracked.init, oldState)
     if interesting:
       setLen(tracked.guards.s, oldFacts)
       addCaseBranchFacts(tracked.guards, n, i)
-    for i in 0 ..< branch.len:
-      track(tracked, branch.sons[i])
+    for i in 0..<branch.len:
+      track(tracked, branch[i])
     if not breaksBlock(branch.lastSon): inc toCover
     for i in oldState..<tracked.init.len:
       addToIntersection(inter, tracked.init[i])
@@ -611,28 +609,28 @@ proc trackCase(tracked: PEffects, n: PNode) =
   setLen(tracked.guards.s, oldFacts)
 
 proc trackIf(tracked: PEffects, n: PNode) =
-  track(tracked, n.sons[0].sons[0])
+  track(tracked, n[0][0])
   let oldFacts = tracked.guards.s.len
-  addFact(tracked.guards, n.sons[0].sons[0])
+  addFact(tracked.guards, n[0][0])
   let oldState = tracked.init.len
 
   var inter: TIntersection = @[]
   var toCover = 0
-  track(tracked, n.sons[0].sons[1])
-  if not breaksBlock(n.sons[0].sons[1]): inc toCover
+  track(tracked, n[0][1])
+  if not breaksBlock(n[0][1]): inc toCover
   for i in oldState..<tracked.init.len:
     addToIntersection(inter, tracked.init[i])
 
   for i in 1..<n.len:
-    let branch = n.sons[i]
+    let branch = n[i]
     setLen(tracked.guards.s, oldFacts)
     for j in 0..i-1:
-      addFactNeg(tracked.guards, n.sons[j].sons[0])
+      addFactNeg(tracked.guards, n[j][0])
     if branch.len > 1:
-      addFact(tracked.guards, branch.sons[0])
+      addFact(tracked.guards, branch[0])
     setLen(tracked.init, oldState)
-    for i in 0 ..< branch.len:
-      track(tracked, branch.sons[i])
+    for i in 0..<branch.len:
+      track(tracked, branch[i])
     if not breaksBlock(branch.lastSon): inc toCover
     for i in oldState..<tracked.init.len:
       addToIntersection(inter, tracked.init[i])
@@ -647,14 +645,14 @@ proc trackBlock(tracked: PEffects, n: PNode) =
   if n.kind in {nkStmtList, nkStmtListExpr}:
     var oldState = -1
     for i in 0..<n.len:
-      if hasSubnodeWith(n.sons[i], nkBreakStmt):
+      if hasSubnodeWith(n[i], nkBreakStmt):
         # block:
         #   x = def
         #   if ...: ... break # some nested break
         #   y = def
         # --> 'y' not defined after block!
         if oldState < 0: oldState = tracked.init.len
-      track(tracked, n.sons[i])
+      track(tracked, n[i])
     if oldState > 0: setLen(tracked.init, oldState)
   else:
     track(tracked, n)
@@ -664,10 +662,10 @@ proc isTrue*(n: PNode): bool =
     n.kind == nkIntLit and n.intVal != 0
 
 proc paramType(op: PType, i: int): PType =
-  if op != nil and i < op.len: result = op.sons[i]
+  if op != nil and i < op.len: result = op[i]
 
 proc cstringCheck(tracked: PEffects; n: PNode) =
-  if n.sons[0].typ.kind == tyCString and (let a = skipConv(n[1]);
+  if n[0].typ.kind == tyCString and (let a = skipConv(n[1]);
       a.typ.kind == tyString and a.kind notin {nkStrLit..nkTripleStrLit}):
     message(tracked.config, n.info, warnUnsafeCode, renderTree(n))
 
@@ -696,11 +694,11 @@ proc track(tracked: PEffects, n: PNode) =
       tracked.owner.flags.incl sfInjectDestructors
   of nkRaiseStmt:
     if n[0].kind != nkEmpty:
-      n.sons[0].info = n.info
-      #throws(tracked.exc, n.sons[0])
-      addEffect(tracked, n.sons[0], useLineInfo=false)
-      for i in 0 ..< safeLen(n):
-        track(tracked, n.sons[i])
+      n[0].info = n.info
+      #throws(tracked.exc, n[0])
+      addEffect(tracked, n[0], useLineInfo=false)
+      for i in 0..<n.safeLen:
+        track(tracked, n[i])
       createTypeBoundOps(tracked, n[0].typ, n.info)
     else:
       # A `raise` with no arguments means we're going to re-raise the exception
@@ -709,7 +707,7 @@ proc track(tracked: PEffects, n: PNode) =
       addEffect(tracked, createRaise(tracked.graph, n))
   of nkCallKinds:
     # p's effects are ours too:
-    var a = n.sons[0]
+    var a = n[0]
     let op = a.typ
     if n.typ != nil:
       if tracked.owner.kind != skMacro and n.typ.skipTypes(abstractVar).kind != tyOpenArray:
@@ -722,7 +720,7 @@ proc track(tracked: PEffects, n: PNode) =
     # calling getAst(templateOrMacro()). Currently, templates and macros
     # are indistinguishable from normal procs (both have tyProc type) and
     # we can detect them only by checking for attached nkEffectList.
-    if op != nil and op.kind == tyProc and op.n.sons[0].kind == nkEffectList:
+    if op != nil and op.kind == tyProc and op.n[0].kind == nkEffectList:
       if a.kind == nkSym:
         if a.sym == tracked.owner: tracked.isRecursive = true
         # even for recursive calls we need to check the lock levels (!):
@@ -730,7 +728,7 @@ proc track(tracked: PEffects, n: PNode) =
         if sfSideEffect in a.sym.flags: markSideEffect(tracked, a)
       else:
         mergeLockLevels(tracked, n, op.lockLevel)
-      var effectList = op.n.sons[0]
+      var effectList = op.n[0]
       if a.kind == nkSym and a.sym.kind == skMethod:
         propagateEffects(tracked, n, a.sym)
       elif isNoEffectList(effectList):
@@ -740,14 +738,14 @@ proc track(tracked: PEffects, n: PNode) =
           assumeTheWorst(tracked, n, op)
           gcsafeAndSideeffectCheck()
       else:
-        mergeEffects(tracked, effectList.sons[exceptionEffects], n)
-        mergeTags(tracked, effectList.sons[tagEffects], n)
+        mergeEffects(tracked, effectList[exceptionEffects], n)
+        mergeTags(tracked, effectList[tagEffects], n)
         gcsafeAndSideeffectCheck()
     if a.kind != nkSym or a.sym.magic != mNBindSym:
-      for i in 1 ..< n.len: trackOperand(tracked, n.sons[i], paramType(op, i), a)
+      for i in 1..<n.len: trackOperand(tracked, n[i], paramType(op, i), a)
     if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
       # may not look like an assignment, but it is:
-      let arg = n.sons[1]
+      let arg = n[1]
       initVarViaNew(tracked, arg)
       if arg.typ.len != 0 and {tfNeedsInit} * arg.typ.lastSon.flags != {}:
         if a.sym.magic == mNewSeq and n[2].kind in {nkCharLit..nkUInt64Lit} and
@@ -760,24 +758,24 @@ proc track(tracked: PEffects, n: PNode) =
       if n[1].typ.len > 0:
         createTypeBoundOps(tracked, n[1].typ.lastSon, n.info)
         createTypeBoundOps(tracked, n[1].typ, n.info)
-    for i in 0 ..< safeLen(n):
-      track(tracked, n.sons[i])
+    for i in 0..<n.safeLen:
+      track(tracked, n[i])
   of nkDotExpr:
     guardDotAccess(tracked, n)
-    for i in 0 ..< n.len: track(tracked, n.sons[i])
+    for i in 0..<n.len: track(tracked, n[i])
   of nkCheckedFieldExpr:
-    track(tracked, n.sons[0])
+    track(tracked, n[0])
     if warnProveField in tracked.config.notes:
       checkFieldAccess(tracked.guards, n, tracked.config)
   of nkTryStmt: trackTryStmt(tracked, n)
   of nkPragma: trackPragmaStmt(tracked, n)
   of nkAsgn, nkFastAsgn:
-    track(tracked, n.sons[1])
-    initVar(tracked, n.sons[0], volatileCheck=true)
-    invalidateFacts(tracked.guards, n.sons[0])
-    track(tracked, n.sons[0])
-    addAsgnFact(tracked.guards, n.sons[0], n.sons[1])
-    notNilCheck(tracked, n.sons[1], n.sons[0].typ)
+    track(tracked, n[1])
+    initVar(tracked, n[0], volatileCheck=true)
+    invalidateFacts(tracked.guards, n[0])
+    track(tracked, n[0])
+    addAsgnFact(tracked.guards, n[0], n[1])
+    notNilCheck(tracked, n[1], n[0].typ)
     when false: cstringCheck(tracked, n)
     if tracked.owner.kind != skMacro:
       createTypeBoundOps(tracked, n[0].typ, n.info)
@@ -788,17 +786,17 @@ proc track(tracked: PEffects, n: PNode) =
       if tracked.owner.kind != skMacro:
         if child.kind == nkVarTuple:
           createTypeBoundOps(tracked, child[^1].typ, child.info)
-          for i in 0..child.len-3:
+          for i in 0..<child.len-2:
             createTypeBoundOps(tracked, child[i].typ, child.info)
         else:
           createTypeBoundOps(tracked, child[0].typ, child.info)
       if child.kind == nkIdentDefs and last.kind != nkEmpty:
-        for i in 0 .. child.len-3:
-          initVar(tracked, child.sons[i], volatileCheck=false)
-          addAsgnFact(tracked.guards, child.sons[i], last)
-          notNilCheck(tracked, last, child.sons[i].typ)
+        for i in 0..<child.len-2:
+          initVar(tracked, child[i], volatileCheck=false)
+          addAsgnFact(tracked.guards, child[i], last)
+          notNilCheck(tracked, last, child[i].typ)
       elif child.kind == nkVarTuple and last.kind != nkEmpty:
-        for i in 0 .. child.len-2:
+        for i in 0..<child.len-1:
           if child[i].kind == nkEmpty or
             child[i].kind == nkSym and child[i].sym.name.s == "_":
             continue
@@ -814,24 +812,24 @@ proc track(tracked: PEffects, n: PNode) =
       track(tracked, last)
   of nkCaseStmt: trackCase(tracked, n)
   of nkWhen, nkIfStmt, nkIfExpr: trackIf(tracked, n)
-  of nkBlockStmt, nkBlockExpr: trackBlock(tracked, n.sons[1])
+  of nkBlockStmt, nkBlockExpr: trackBlock(tracked, n[1])
   of nkWhileStmt:
-    track(tracked, n.sons[0])
+    track(tracked, n[0])
     # 'while true' loop?
-    if isTrue(n.sons[0]):
-      trackBlock(tracked, n.sons[1])
+    if isTrue(n[0]):
+      trackBlock(tracked, n[1])
     else:
       # loop may never execute:
       let oldState = tracked.init.len
       let oldFacts = tracked.guards.s.len
-      addFact(tracked.guards, n.sons[0])
-      track(tracked, n.sons[1])
+      addFact(tracked.guards, n[0])
+      track(tracked, n[1])
       setLen(tracked.init, oldState)
       setLen(tracked.guards.s, oldFacts)
   of nkForStmt, nkParForStmt:
     # we are very conservative here and assume the loop is never executed:
     let oldState = tracked.init.len
-    for i in 0 .. n.len-3:
+    for i in 0..<n.len-2:
       let it = n[i]
       track(tracked, it)
       if tracked.owner.kind != skMacro:
@@ -840,8 +838,8 @@ proc track(tracked: PEffects, n: PNode) =
             createTypeBoundOps(tracked, x.typ, x.info)
         else:
           createTypeBoundOps(tracked, it.typ, it.info)
-    let iterCall = n[n.len-2]
-    let loopBody = n[n.len-1]
+    let iterCall = n[^2]
+    let loopBody = n[^1]
     if tracked.owner.kind != skMacro and iterCall.safeLen > 1:
       # XXX this is a bit hacky:
       if iterCall[1].typ != nil and iterCall[1].typ.skipTypes(abstractVar).kind notin {tyVarargs, tyOpenArray}:
@@ -850,26 +848,26 @@ proc track(tracked: PEffects, n: PNode) =
     track(tracked, loopBody)
     setLen(tracked.init, oldState)
   of nkObjConstr:
-    when false: track(tracked, n.sons[0])
+    when false: track(tracked, n[0])
     let oldFacts = tracked.guards.s.len
-    for i in 1 ..< n.len:
-      let x = n.sons[i]
+    for i in 1..<n.len:
+      let x = n[i]
       track(tracked, x)
-      if x.sons[0].kind == nkSym and sfDiscriminant in x.sons[0].sym.flags:
+      if x[0].kind == nkSym and sfDiscriminant in x[0].sym.flags:
         addDiscriminantFact(tracked.guards, x)
     setLen(tracked.guards.s, oldFacts)
     if tracked.owner.kind != skMacro:
       createTypeBoundOps(tracked, n.typ, n.info)
   of nkPragmaBlock:
-    let pragmaList = n.sons[0]
+    let pragmaList = n[0]
     let oldLocked = tracked.locked.len
     let oldLockLevel = tracked.currLockLevel
     var enforcedGcSafety = false
     var enforceNoSideEffects = false
-    for i in 0 ..< pragmaList.len:
-      let pragma = whichPragma(pragmaList.sons[i])
+    for i in 0..<pragmaList.len:
+      let pragma = whichPragma(pragmaList[i])
       if pragma == wLocks:
-        lockLocations(tracked, pragmaList.sons[i])
+        lockLocations(tracked, pragmaList[i])
       elif pragma == wGcSafe:
         enforcedGcSafety = true
       elif pragma == wNoSideEffect:
@@ -885,15 +883,15 @@ proc track(tracked: PEffects, n: PNode) =
       nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef:
     discard
   of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv:
-    if n.len == 2: track(tracked, n.sons[1])
+    if n.len == 2: track(tracked, n[1])
   of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
-    if n.len == 1: track(tracked, n.sons[0])
+    if n.len == 1: track(tracked, n[0])
   of nkBracket:
-    for i in 0 ..< safeLen(n): track(tracked, n.sons[i])
+    for i in 0..<n.safeLen: track(tracked, n[i])
     if tracked.owner.kind != skMacro:
       createTypeBoundOps(tracked, n.typ, n.info)
   else:
-    for i in 0 ..< safeLen(n): track(tracked, n.sons[i])
+    for i in 0..<n.safeLen: track(tracked, n[i])
 
 proc subtypeRelation(g: ModuleGraph; spec, real: PNode): bool =
   result = safeInheritanceDiff(g.excType(real), spec.typ) <= 0
@@ -905,7 +903,7 @@ proc checkRaisesSpec(g: ModuleGraph; spec, real: PNode, msg: string, hints: bool
   var used = initIntSet()
   for r in items(real):
     block search:
-      for s in 0 ..< spec.len:
+      for s in 0..<spec.len:
         if effectPredicate(g, spec[s], r):
           used.incl(s)
           break search
@@ -915,23 +913,23 @@ proc checkRaisesSpec(g: ModuleGraph; spec, real: PNode, msg: string, hints: bool
       popInfoContext(g.config)
   # hint about unnecessarily listed exception types:
   if hints:
-    for s in 0 ..< spec.len:
+    for s in 0..<spec.len:
       if not used.contains(s):
         message(g.config, spec[s].info, hintXDeclaredButNotUsed, renderTree(spec[s]))
 
 proc checkMethodEffects*(g: ModuleGraph; disp, branch: PSym) =
   ## checks for consistent effects for multi methods.
-  let actual = branch.typ.n.sons[0]
+  let actual = branch.typ.n[0]
   if actual.len != effectListLen: return
 
-  let p = disp.ast.sons[pragmasPos]
+  let p = disp.ast[pragmasPos]
   let raisesSpec = effectSpec(p, wRaises)
   if not isNil(raisesSpec):
-    checkRaisesSpec(g, raisesSpec, actual.sons[exceptionEffects],
+    checkRaisesSpec(g, raisesSpec, actual[exceptionEffects],
       "can raise an unlisted exception: ", hints=off, subtypeRelation)
   let tagsSpec = effectSpec(p, wTags)
   if not isNil(tagsSpec):
-    checkRaisesSpec(g, tagsSpec, actual.sons[tagEffects],
+    checkRaisesSpec(g, tagsSpec, actual[tagEffects],
       "can have an unlisted effect: ", hints=off, subtypeRelation)
   if sfThread in disp.flags and notGcSafe(branch.typ):
     localError(g.config, branch.info, "base method is GC-safe, but '$1' is not" %
@@ -963,14 +961,14 @@ proc setEffectsForProcType*(g: ModuleGraph; t: PType, n: PNode) =
 
 proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; t: var TEffects; c: PContext) =
   newSeq(effects.sons, effectListLen)
-  effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info)
-  effects.sons[tagEffects] = newNodeI(nkArgList, s.info)
-  effects.sons[usesEffects] = g.emptyNode
-  effects.sons[writeEffects] = g.emptyNode
-  effects.sons[pragmasEffects] = g.emptyNode
-
-  t.exc = effects.sons[exceptionEffects]
-  t.tags = effects.sons[tagEffects]
+  effects[exceptionEffects] = newNodeI(nkArgList, s.info)
+  effects[tagEffects] = newNodeI(nkArgList, s.info)
+  effects[usesEffects] = g.emptyNode
+  effects[writeEffects] = g.emptyNode
+  effects[pragmasEffects] = g.emptyNode
+
+  t.exc = effects[exceptionEffects]
+  t.tags = effects[tagEffects]
   t.owner = s
   t.ownerModule = s.getModule
   t.init = @[]
@@ -983,7 +981,7 @@ proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; t: var TEffects; c: PC
 
 proc trackProc*(c: PContext; s: PSym, body: PNode) =
   let g = c.graph
-  var effects = s.typ.n.sons[0]
+  var effects = s.typ.n[0]
   if effects.kind != nkEffectList: return
   # effects already computed?
   if sfForward in s.flags: return
@@ -995,32 +993,32 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
 
   if s.kind != skMacro:
     let params = s.typ.n
-    for i in 1 ..< params.len:
+    for i in 1..<params.len:
       let param = params[i].sym
       if isSinkTypeForParam(param.typ):
         createTypeBoundOps(t.graph, t.c, param.typ, param.info)
 
-  if not isEmptyType(s.typ.sons[0]) and
-      ({tfNeedsInit, tfNotNil} * s.typ.sons[0].flags != {} or
-      s.typ.sons[0].skipTypes(abstractInst).kind == tyVar) and
+  if not isEmptyType(s.typ[0]) and
+      ({tfNeedsInit, tfNotNil} * s.typ[0].flags != {} or
+      s.typ[0].skipTypes(abstractInst).kind == tyVar) and
       s.kind in {skProc, skFunc, skConverter, skMethod}:
-    var res = s.ast.sons[resultPos].sym # get result symbol
+    var res = s.ast[resultPos].sym # get result symbol
     if res.id notin t.init:
       message(g.config, body.info, warnProveInit, "result")
-  let p = s.ast.sons[pragmasPos]
+  let p = s.ast[pragmasPos]
   let raisesSpec = effectSpec(p, wRaises)
   if not isNil(raisesSpec):
     checkRaisesSpec(g, raisesSpec, t.exc, "can raise an unlisted exception: ",
                     hints=on, subtypeRelation)
     # after the check, use the formal spec:
-    effects.sons[exceptionEffects] = raisesSpec
+    effects[exceptionEffects] = raisesSpec
 
   let tagsSpec = effectSpec(p, wTags)
   if not isNil(tagsSpec):
     checkRaisesSpec(g, tagsSpec, t.tags, "can have an unlisted effect: ",
                     hints=off, subtypeRelation)
     # after the check, use the formal spec:
-    effects.sons[tagEffects] = tagsSpec
+    effects[tagEffects] = tagsSpec
 
   if sfThread in s.flags and t.gcUnsafe:
     if optThreads in g.config.globalOptions and optThreadAnalysis in g.config.globalOptions:
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 3cdf1efb2..3abee2faf 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -42,10 +42,10 @@ const
 proc semDiscard(c: PContext, n: PNode): PNode =
   result = n
   checkSonsLen(n, 1, c.config)
-  if n.sons[0].kind != nkEmpty:
-    n.sons[0] = semExprWithType(c, n.sons[0])
-    let sonType = n.sons[0].typ
-    let sonKind = n.sons[0].kind
+  if n[0].kind != nkEmpty:
+    n[0] = semExprWithType(c, n[0])
+    let sonType = n[0].typ
+    let sonKind = n[0].kind
     if isEmptyType(sonType) or sonType.kind in {tyNone, tyTypeDesc} or sonKind == nkTypeOfExpr:
       localError(c.config, n.info, errInvalidDiscard)
     if sonType.kind == tyProc and sonKind notin nkCallKinds:
@@ -55,19 +55,19 @@ proc semDiscard(c: PContext, n: PNode): PNode =
 proc semBreakOrContinue(c: PContext, n: PNode): PNode =
   result = n
   checkSonsLen(n, 1, c.config)
-  if n.sons[0].kind != nkEmpty:
+  if n[0].kind != nkEmpty:
     if n.kind != nkContinueStmt:
       var s: PSym
-      case n.sons[0].kind
-      of nkIdent: s = lookUp(c, n.sons[0])
-      of nkSym: s = n.sons[0].sym
+      case n[0].kind
+      of nkIdent: s = lookUp(c, n[0])
+      of nkSym: s = n[0].sym
       else: illFormedAst(n, c.config)
       s = getGenSym(c, s)
       if s.kind == skLabel and s.owner.id == c.p.owner.id:
         var x = newSymNode(s)
         x.info = n.info
         incl(s.flags, sfUsed)
-        n.sons[0] = x
+        n[0] = x
         suggestSym(c.config, x.info, s, c.graph.usageSym)
         onUse(x.info, s)
       else:
@@ -80,7 +80,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
 
 proc semAsm(c: PContext, n: PNode): PNode =
   checkSonsLen(n, 2, c.config)
-  var marker = pragmaAsm(c, n.sons[0])
+  var marker = pragmaAsm(c, n[0])
   if marker == '\0': marker = '`' # default marker
   result = semAsmOrEmit(c, n, marker)
 
@@ -88,12 +88,12 @@ proc semWhile(c: PContext, n: PNode; flags: TExprFlags): PNode =
   result = n
   checkSonsLen(n, 2, c.config)
   openScope(c)
-  n.sons[0] = forceBool(c, semExprWithType(c, n.sons[0]))
+  n[0] = forceBool(c, semExprWithType(c, n[0]))
   inc(c.p.nestedLoopCounter)
-  n.sons[1] = semStmt(c, n.sons[1], flags)
+  n[1] = semStmt(c, n[1], flags)
   dec(c.p.nestedLoopCounter)
   closeScope(c)
-  if n.sons[1].typ == c.enforceVoidContext:
+  if n[1].typ == c.enforceVoidContext:
     result.typ = c.enforceVoidContext
   elif efInTypeof in flags:
     result.typ = n[1].typ
@@ -121,8 +121,8 @@ proc implicitlyDiscardable(n: PNode): bool =
   var n = n
   while n.kind in skipForDiscardable: n = n.lastSon
   result = n.kind == nkRaiseStmt or
-           (isCallExpr(n) and n.sons[0].kind == nkSym and
-           sfDiscardable in n.sons[0].sym.flags)
+           (isCallExpr(n) and n[0].kind == nkSym and
+           sfDiscardable in n[0].sym.flags)
 
 proc fixNilType(c: PContext; n: PNode) =
   if isAtom(n):
@@ -156,18 +156,18 @@ proc semIf(c: PContext, n: PNode; flags: TExprFlags): PNode =
   result = n
   var typ = commonTypeBegin
   var hasElse = false
-  for i in 0 ..< len(n):
-    var it = n.sons[i]
+  for i in 0..<n.len:
+    var it = n[i]
     if it.len == 2:
       openScope(c)
-      it.sons[0] = forceBool(c, semExprWithType(c, it.sons[0]))
-      it.sons[1] = semExprBranch(c, it.sons[1])
-      typ = commonType(typ, it.sons[1])
+      it[0] = forceBool(c, semExprWithType(c, it[0]))
+      it[1] = semExprBranch(c, it[1])
+      typ = commonType(typ, it[1])
       closeScope(c)
     elif it.len == 1:
       hasElse = true
-      it.sons[0] = semExprBranchScope(c, it.sons[0])
-      typ = commonType(typ, it.sons[0])
+      it[0] = semExprBranchScope(c, it[0])
+      typ = commonType(typ, it[0])
     else: illFormedAst(it, c.config)
   if isEmptyType(typ) or typ.kind in {tyNil, tyUntyped} or
       (not hasElse and efInTypeof notin flags):
@@ -178,8 +178,8 @@ proc semIf(c: PContext, n: PNode; flags: TExprFlags): PNode =
   else:
     for it in n:
       let j = it.len-1
-      if not endsInNoReturn(it.sons[j]):
-        it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info)
+      if not endsInNoReturn(it[j]):
+        it[j] = fitNode(c, typ, it[j], it[j].info)
     result.kind = nkIfExpr
     result.typ = typ
 
@@ -207,11 +207,11 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
   n[0] = semExprBranchScope(c, n[0])
   typ = commonType(typ, n[0].typ)
 
-  var last = len(n) - 1
+  var last = n.len - 1
   var catchAllExcepts = 0
 
-  for i in 1 .. last:
-    let a = n.sons[i]
+  for i in 1..last:
+    let a = n[i]
     checkMinSonsLen(a, 1, c.config)
     openScope(c)
     if a.kind == nkExceptBranch:
@@ -241,7 +241,7 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
           # cannot be followed by a ``except KeyError, ... : body`` block
           inc catchAllExcepts
         var isNative, isImported: bool
-        for j in 0..a.len-2:
+        for j in 0..<a.len-1:
           let tmp = semExceptBranchType(a[j])
           if tmp: isImported = true
           else: isNative = true
@@ -269,24 +269,24 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
 
   dec c.p.inTryStmt
   if isEmptyType(typ) or typ.kind in {tyNil, tyUntyped}:
-    discardCheck(c, n.sons[0], flags)
-    for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon, flags)
+    discardCheck(c, n[0], flags)
+    for i in 1..<n.len: discardCheck(c, n[i].lastSon, flags)
     if typ == c.enforceVoidContext:
       result.typ = c.enforceVoidContext
   else:
     if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon, flags)
-    n.sons[0] = fitNode(c, typ, n.sons[0], n.sons[0].info)
+    n[0] = fitNode(c, typ, n[0], n[0].info)
     for i in 1..last:
-      var it = n.sons[i]
+      var it = n[i]
       let j = it.len-1
-      if not endsInNoReturn(it.sons[j]):
-        it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info)
+      if not endsInNoReturn(it[j]):
+        it[j] = fitNode(c, typ, it[j], it[j].info)
     result.typ = typ
 
 proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
   result = fitNode(c, typ, n, n.info)
   if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
-    let r1 = result.sons[1]
+    let r1 = result[1]
     if r1.kind in {nkCharLit..nkUInt64Lit} and typ.skipTypes(abstractRange).kind in {tyFloat..tyFloat128}:
       result = newFloatNode(nkFloatLit, BiggestFloat r1.intVal)
       result.info = n.info
@@ -307,8 +307,8 @@ proc findShadowedVar(c: PContext, v: PSym): PSym =
       return shadowed
 
 proc identWithin(n: PNode, s: PIdent): bool =
-  for i in 0 .. n.safeLen-1:
-    if identWithin(n.sons[i], s): return true
+  for i in 0..n.safeLen-1:
+    if identWithin(n[i], s): return true
   result = n.kind == nkSym and n.sym.name.id == s.id
 
 proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
@@ -326,9 +326,9 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
   proc getLineInfo(n: PNode): TLineInfo =
     case n.kind
     of nkPostfix:
-      getLineInfo(n.sons[1])
+      getLineInfo(n[1])
     of nkAccQuoted, nkPragmaExpr:
-      getLineInfo(n.sons[0])
+      getLineInfo(n[0])
     else:
       n.info
   let info = getLineInfo(n)
@@ -345,8 +345,7 @@ proc checkNilable(c: PContext; v: PSym) =
 #include liftdestructors
 
 proc addToVarSection(c: PContext; result: PNode; orig, identDefs: PNode) =
-  let L = identDefs.len
-  let value = identDefs[L-1]
+  let value = identDefs[^1]
   if result.kind == nkStmtList:
     let o = copyNode(orig)
     o.add identDefs
@@ -362,17 +361,16 @@ proc isDiscardUnderscore(v: PSym): bool =
 proc semUsing(c: PContext; n: PNode): PNode =
   result = c.graph.emptyNode
   if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "using")
-  for i in 0 ..< len(n):
-    var a = n.sons[i]
+  for i in 0..<n.len:
+    var a = n[i]
     if c.config.cmd == cmdIdeTools: suggestStmt(c, a)
     if a.kind == nkCommentStmt: continue
     if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a, c.config)
     checkMinSonsLen(a, 3, c.config)
-    var length = len(a)
-    if a.sons[length-2].kind != nkEmpty:
-      let typ = semTypeNode(c, a.sons[length-2], nil)
-      for j in 0 .. length-3:
-        let v = semIdentDef(c, a.sons[j], skParam)
+    if a[^2].kind != nkEmpty:
+      let typ = semTypeNode(c, a[^2], nil)
+      for j in 0..<a.len-2:
+        let v = semIdentDef(c, a[j], skParam)
         styleCheckDef(c.config, v)
         onDef(a[j].info, v)
         v.typ = typ
@@ -380,7 +378,7 @@ proc semUsing(c: PContext; n: PNode): PNode =
     else:
       localError(c.config, a.info, "'using' section must have a type")
     var def: PNode
-    if a.sons[length-1].kind != nkEmpty:
+    if a[^1].kind != nkEmpty:
       localError(c.config, a.info, "'using' sections cannot contain assignments")
 
 proc hasEmpty(typ: PType): bool =
@@ -397,14 +395,14 @@ proc makeDeref(n: PNode): PNode =
   t = skipTypes(t, {tyGenericInst, tyAlias, tySink, tyOwned})
   result = n
   if t.kind in {tyVar, tyLent}:
-    result = newNodeIT(nkHiddenDeref, n.info, t.sons[0])
-    addSon(result, n)
-    t = skipTypes(t.sons[0], {tyGenericInst, tyAlias, tySink, tyOwned})
+    result = newNodeIT(nkHiddenDeref, n.info, t[0])
+    result.add n
+    t = skipTypes(t[0], {tyGenericInst, tyAlias, tySink, tyOwned})
   while t.kind in {tyPtr, tyRef}:
     var a = result
     let baseTyp = t.lastSon
     result = newNodeIT(nkHiddenDeref, n.info, baseTyp)
-    addSon(result, a)
+    result.add a
     t = skipTypes(baseTyp, {tyGenericInst, tyAlias, tySink, tyOwned})
 
 proc fillPartialObject(c: PContext; n: PNode; typ: PType) =
@@ -415,10 +413,10 @@ proc fillPartialObject(c: PContext; n: PNode; typ: PType) =
     if obj.kind == tyObject and tfPartial in obj.flags:
       let field = newSym(skField, getIdent(c.cache, y.s), obj.sym, n[1].info)
       field.typ = skipIntLit(typ)
-      field.position = len(obj.n)
-      addSon(obj.n, newSymNode(field))
-      n.sons[0] = makeDeref x
-      n.sons[1] = newSymNode(field)
+      field.position = obj.n.len
+      obj.n.add newSymNode(field)
+      n[0] = makeDeref x
+      n[1] = newSymNode(field)
       n.typ = field.typ
     else:
       localError(c.config, n.info, "implicit object field construction " &
@@ -436,21 +434,20 @@ proc setVarType(c: PContext; v: PSym, typ: PType) =
 proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
   var b: PNode
   result = copyNode(n)
-  for i in 0 ..< len(n):
-    var a = n.sons[i]
+  for i in 0..<n.len:
+    var a = n[i]
     if c.config.cmd == cmdIdeTools: suggestStmt(c, a)
     if a.kind == nkCommentStmt: continue
     if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a, c.config)
     checkMinSonsLen(a, 3, c.config)
-    var length = len(a)
 
     var typ: PType = nil
-    if a.sons[length-2].kind != nkEmpty:
-      typ = semTypeNode(c, a.sons[length-2], nil)
+    if a[^2].kind != nkEmpty:
+      typ = semTypeNode(c, a[^2], nil)
 
     var def: PNode = c.graph.emptyNode
-    if a.sons[length-1].kind != nkEmpty:
-      def = semExprWithType(c, a.sons[length-1], {efAllowDestructor})
+    if a[^1].kind != nkEmpty:
+      def = semExprWithType(c, a[^1], {efAllowDestructor})
       if def.typ.kind == tyProc and def.kind == nkSym:
         if def.sym.kind == skMacro:
           localError(c.config, def.info, errCannotAssignMacroSymbol % "variable")
@@ -498,26 +495,26 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
     if a.kind == nkVarTuple:
       if tup.kind != tyTuple:
         localError(c.config, a.info, errXExpected, "tuple")
-      elif length-2 != len(tup):
+      elif a.len-2 != tup.len:
         localError(c.config, a.info, errWrongNumberOfVariables)
       b = newNodeI(nkVarTuple, a.info)
-      newSons(b, length)
+      newSons(b, a.len)
       # keep type desc for doc generator
       # NOTE: at the moment this is always ast.emptyNode, see parser.nim
-      b.sons[length-2] = a.sons[length-2]
-      b.sons[length-1] = def
+      b[^2] = a[^2]
+      b[^1] = def
       addToVarSection(c, result, n, b)
     elif tup.kind == tyTuple and def.kind in {nkPar, nkTupleConstr} and
         a.kind == nkIdentDefs and a.len > 3:
       message(c.config, a.info, warnEachIdentIsTuple)
 
-    for j in 0 .. length-3:
+    for j in 0..<a.len-2:
       if a[j].kind == nkDotExpr:
         fillPartialObject(c, a[j],
-          if a.kind != nkVarTuple: typ else: tup.sons[j])
+          if a.kind != nkVarTuple: typ else: tup[j])
         addToVarSection(c, result, n, a)
         continue
-      var v = semIdentDef(c, a.sons[j], symkind)
+      var v = semIdentDef(c, a[j], symkind)
       styleCheckDef(c.config, v)
       onDef(a[j].info, v)
       if sfGenSym notin v.flags:
@@ -540,10 +537,10 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
         if importantComments(c.config):
           # keep documentation information:
           b.comment = a.comment
-        addSon(b, newSymNode(v))
+        b.add newSymNode(v)
         # keep type desc for doc generator
-        addSon(b, a.sons[length-2])
-        addSon(b, copyTree(def))
+        b.add a[^2]
+        b.add copyTree(def)
         addToVarSection(c, result, n, b)
         if optOldAst in c.config.options:
           if def.kind != nkEmpty:
@@ -559,19 +556,19 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
             ast.add p
           else:
             ast.add newSymNode(v)
-          ast.add a.sons[length-2].copyTree
+          ast.add a[^2].copyTree
           ast.add def
           v.ast = ast
       else:
         if def.kind in {nkPar, nkTupleConstr}: v.ast = def[j]
         # bug #7663, for 'nim check' this can be a non-tuple:
-        if tup.kind == tyTuple: setVarType(c, v, tup.sons[j])
+        if tup.kind == tyTuple: setVarType(c, v, tup[j])
         else: v.typ = tup
-        b.sons[j] = newSymNode(v)
+        b[j] = newSymNode(v)
       checkNilable(c, v)
       if sfCompileTime in v.flags:
         var x = newNodeI(result.kind, v.info)
-        addSon(x, result[i])
+        x.add result[i]
         vm.setupCompileTimeVar(c.module, c.graph, x)
       if v.flags * {sfGlobal, sfThread} == {sfGlobal}:
         message(c.config, v.info, hintGlobalVar)
@@ -579,17 +576,16 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
 proc semConst(c: PContext, n: PNode): PNode =
   result = copyNode(n)
   inc c.inStaticContext
-  for i in 0 ..< len(n):
-    var a = n.sons[i]
+  for i in 0..<n.len:
+    var a = n[i]
     if c.config.cmd == cmdIdeTools: suggestStmt(c, a)
     if a.kind == nkCommentStmt: continue
     if a.kind notin {nkConstDef, nkVarTuple}: illFormedAst(a, c.config)
     checkMinSonsLen(a, 3, c.config)
-    var length = len(a)
 
     var typ: PType = nil
-    if a.sons[length-2].kind != nkEmpty:
-      typ = semTypeNode(c, a.sons[length-2], nil)
+    if a[^2].kind != nkEmpty:
+      typ = semTypeNode(c, a[^2], nil)
 
     # don't evaluate here since the type compatibility check below may add a converter
     var def = semExprWithType(c, a[^1])
@@ -615,7 +611,7 @@ proc semConst(c: PContext, n: PNode): PNode =
     # evaluate the node
     def = semConstExpr(c, def)
     if def == nil:
-      localError(c.config, a.sons[length-1].info, errConstExprExpected)
+      localError(c.config, a[^1].info, errConstExprExpected)
       continue
     if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit:
       localError(c.config, a.info, "invalid type for const: " & typeToString(typ))
@@ -625,15 +621,15 @@ proc semConst(c: PContext, n: PNode): PNode =
     if a.kind == nkVarTuple:
       if typ.kind != tyTuple:
         localError(c.config, a.info, errXExpected, "tuple")
-      elif length-2 != len(typ):
+      elif a.len-2 != typ.len:
         localError(c.config, a.info, errWrongNumberOfVariables)
       b = newNodeI(nkVarTuple, a.info)
-      newSons(b, length)
-      b.sons[length-2] = a.sons[length-2]
-      b.sons[length-1] = def
+      newSons(b, a.len)
+      b[^2] = a[^2]
+      b[^1] = def
 
-    for j in 0 ..< length-2:
-      var v = semIdentDef(c, a.sons[j], skConst)
+    for j in 0..<a.len-2:
+      var v = semIdentDef(c, a[j], skConst)
       if sfGenSym notin v.flags: addInterfaceDecl(c, v)
       elif v.owner == nil: v.owner = getCurrOwner(c)
       styleCheckDef(c.config, v)
@@ -644,77 +640,76 @@ proc semConst(c: PContext, n: PNode): PNode =
         v.ast = def               # no need to copy
         b = newNodeI(nkConstDef, a.info)
         if importantComments(c.config): b.comment = a.comment
-        addSon(b, newSymNode(v))
-        addSon(b, a.sons[1])
-        addSon(b, copyTree(def))
+        b.add newSymNode(v)
+        b.add a[1]
+        b.add copyTree(def)
       else:
-        setVarType(c, v, typ.sons[j])
+        setVarType(c, v, typ[j])
         v.ast = if def[j].kind != nkExprColonExpr: def[j]
-                else: def[j].sons[1]
-        b.sons[j] = newSymNode(v)
-    addSon(result,b)
+                else: def[j][1]
+        b[j] = newSymNode(v)
+    result.add b
   dec c.inStaticContext
 
 include semfields
 
 
 proc symForVar(c: PContext, n: PNode): PSym =
-  let m = if n.kind == nkPragmaExpr: n.sons[0] else: n
+  let m = if n.kind == nkPragmaExpr: n[0] else: n
   result = newSymG(skForVar, m, c)
   styleCheckDef(c.config, result)
   onDef(n.info, result)
   if n.kind == nkPragmaExpr:
-    pragma(c, result, n.sons[1], forVarPragmas)
+    pragma(c, result, n[1], forVarPragmas)
 
 proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
   result = n
-  var length = len(n)
-  let iterBase = n.sons[length-2].typ
+  let iterBase = n[^2].typ
   var iter = skipTypes(iterBase, {tyGenericInst, tyAlias, tySink, tyOwned})
   var iterAfterVarLent = iter.skipTypes({tyLent, tyVar})
-  # length == 3 means that there is one for loop variable
+  # n.len == 3 means that there is one for loop variable
   # and thus no tuple unpacking:
-  if iterAfterVarLent.kind != tyTuple or length == 3:
-    if length == 3:
-      if n.sons[0].kind == nkVarTuple:
-        if len(n[0])-1 != len(iterAfterVarLent):
+  if iterAfterVarLent.kind != tyTuple or n.len == 3:
+    if n.len == 3:
+      if n[0].kind == nkVarTuple:
+        if n[0].len-1 != iterAfterVarLent.len:
           localError(c.config, n[0].info, errWrongNumberOfVariables)
-        for i in 0 ..< len(n[0])-1:
+        for i in 0..<n[0].len-1:
           var v = symForVar(c, n[0][i])
           if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal)
           case iter.kind
           of tyVar:
             v.typ = newTypeS(tyVar, c)
-            v.typ.sons.add iterAfterVarLent[i]
+            v.typ.add iterAfterVarLent[i]
             if tfVarIsPtr in iter.flags:
               v.typ.flags.incl tfVarIsPtr
           of tyLent:
             v.typ = newTypeS(tyLent, c)
-            v.typ.sons.add iterAfterVarLent[i]
+            v.typ.add iterAfterVarLent[i]
             if tfVarIsPtr in iter.flags:
               v.typ.flags.incl tfVarIsPtr
           else:
-            v.typ = iter.sons[i]
-          n.sons[0][i] = newSymNode(v)
+            v.typ = iter[i]
+          n[0][i] = newSymNode(v)
           if sfGenSym notin v.flags: addDecl(c, v)
           elif v.owner == nil: v.owner = getCurrOwner(c)
       else:
-        var v = symForVar(c, n.sons[0])
+        var v = symForVar(c, n[0])
         if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal)
         # BUGFIX: don't use `iter` here as that would strip away
         # the ``tyGenericInst``! See ``tests/compile/tgeneric.nim``
         # for an example:
         v.typ = iterBase
-        n.sons[0] = newSymNode(v)
+        n[0] = newSymNode(v)
         if sfGenSym notin v.flags: addDecl(c, v)
         elif v.owner == nil: v.owner = getCurrOwner(c)
     else:
       localError(c.config, n.info, errWrongNumberOfVariables)
-  elif length-2 != len(iterAfterVarLent):
+  elif n.len-2 != iterAfterVarLent.len:
     localError(c.config, n.info, errWrongNumberOfVariables)
   else:
-    for i in 0 .. length - 3:
-      if n.sons[i].kind == nkVarTuple:
+    for i in 0..<n.len - 2:
+      if n[i].kind == nkVarTuple:
         var mutable = false
         var isLent = false
         case iter[i].kind
@@ -726,47 +721,47 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
           iter[i] = iter[i].skipTypes({tyLent})
         else: discard
 
-        if len(n[i])-1 != len(iter[i]):
+        if n[i].len-1 != iter[i].len:
           localError(c.config, n[i].info, errWrongNumberOfVariables)
-        for j in 0 ..< len(n[i])-1:
+        for j in 0..<n[i].len-1:
           var v = symForVar(c, n[i][j])
           if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal)
           if mutable:
             v.typ = newTypeS(tyVar, c)
-            v.typ.sons.add iter[i][j]
+            v.typ.add iter[i][j]
           elif isLent:
             v.typ = newTypeS(tyLent, c)
-            v.typ.sons.add iter[i][j]
+            v.typ.add iter[i][j]
           else:
             v.typ = iter[i][j]
-          n.sons[i][j] = newSymNode(v)
+          n[i][j] = newSymNode(v)
           if not isDiscardUnderscore(v): addDecl(c, v)
           elif v.owner == nil: v.owner = getCurrOwner(c)
       else:
-        var v = symForVar(c, n.sons[i])
+        var v = symForVar(c, n[i])
         if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal)
         case iter.kind
         of tyVar:
           v.typ = newTypeS(tyVar, c)
-          v.typ.sons.add iterAfterVarLent[i]
+          v.typ.add iterAfterVarLent[i]
           if tfVarIsPtr in iter.flags:
             v.typ.flags.incl tfVarIsPtr
         of tyLent:
           v.typ = newTypeS(tyLent, c)
-          v.typ.sons.add iterAfterVarLent[i]
+          v.typ.add iterAfterVarLent[i]
           if tfVarIsPtr in iter.flags:
             v.typ.flags.incl tfVarIsPtr
         else:
-          v.typ = iter.sons[i]
-        n.sons[i] = newSymNode(v)
+          v.typ = iter[i]
+        n[i] = newSymNode(v)
         if sfGenSym notin v.flags:
           if not isDiscardUnderscore(v): addDecl(c, v)
         elif v.owner == nil: v.owner = getCurrOwner(c)
   inc(c.p.nestedLoopCounter)
   openScope(c)
-  n.sons[length-1] = semExprBranch(c, n.sons[length-1], flags)
+  n[^1] = semExprBranch(c, n[^1], flags)
   if efInTypeof notin flags:
-    discardCheck(c, n.sons[length-1], flags)
+    discardCheck(c, n[^1], flags)
   closeScope(c)
   dec(c.p.nestedLoopCounter)
 
@@ -780,7 +775,7 @@ proc implicitIterator(c: PContext, it: string, arg: PNode): PNode =
   result = semExprNoDeref(c, result, {efWantIterator})
 
 proc isTrivalStmtExpr(n: PNode): bool =
-  for i in 0 .. n.len-2:
+  for i in 0..<n.len-1:
     if n[i].kind notin {nkEmpty, nkCommentStmt}:
       return false
   result = true
@@ -838,7 +833,7 @@ proc handleCaseStmtMacro(c: PContext; n: PNode): PNode =
     onUse(n[0].info, match)
 
     # but pass 'n' to the 'match' macro, not 'n[0]':
-    r.call.sons[1] = n
+    r.call[1] = n
     let toExpand = semResolvedCall(c, r, r.call, {})
     case match.kind
     of skMacro: result = semMacroExpr(c, toExpand, toExpand, match, {})
@@ -852,41 +847,40 @@ proc handleCaseStmtMacro(c: PContext; n: PNode): PNode =
 
 proc semFor(c: PContext, n: PNode; flags: TExprFlags): PNode =
   checkMinSonsLen(n, 3, c.config)
-  var length = len(n)
   if forLoopMacros in c.features:
     result = handleForLoopMacro(c, n)
     if result != nil: return result
   openScope(c)
   result = n
-  n.sons[length-2] = semExprNoDeref(c, n.sons[length-2], {efWantIterator})
-  var call = n.sons[length-2]
+  n[^2] = semExprNoDeref(c, n[^2], {efWantIterator})
+  var call = n[^2]
   if call.kind == nkStmtListExpr and isTrivalStmtExpr(call):
     call = call.lastSon
-    n.sons[length-2] = call
+    n[^2] = call
   let isCallExpr = call.kind in nkCallKinds
   if isCallExpr and call[0].kind == nkSym and
       call[0].sym.magic in {mFields, mFieldPairs, mOmpParFor}:
-    if call.sons[0].sym.magic == mOmpParFor:
+    if call[0].sym.magic == mOmpParFor:
       result = semForVars(c, n, flags)
       result.kind = nkParForStmt
     else:
-      result = semForFields(c, n, call.sons[0].sym.magic)
-  elif isCallExpr and isClosureIterator(call.sons[0].typ.skipTypes(abstractInst)):
+      result = semForFields(c, n, call[0].sym.magic)
+  elif isCallExpr and isClosureIterator(call[0].typ.skipTypes(abstractInst)):
     # first class iterator:
     result = semForVars(c, n, flags)
-  elif not isCallExpr or call.sons[0].kind != nkSym or
-      call.sons[0].sym.kind != skIterator:
-    if length == 3:
-      n.sons[length-2] = implicitIterator(c, "items", n.sons[length-2])
-    elif length == 4:
-      n.sons[length-2] = implicitIterator(c, "pairs", n.sons[length-2])
+  elif not isCallExpr or call[0].kind != nkSym or
+      call[0].sym.kind != skIterator:
+    if n.len == 3:
+      n[^2] = implicitIterator(c, "items", n[^2])
+    elif n.len == 4:
+      n[^2] = implicitIterator(c, "pairs", n[^2])
     else:
-      localError(c.config, n.sons[length-2].info, "iterator within for loop context expected")
+      localError(c.config, n[^2].info, "iterator within for loop context expected")
     result = semForVars(c, n, flags)
   else:
     result = semForVars(c, n, flags)
   # propagate any enforced VoidContext:
-  if n.sons[length-1].typ == c.enforceVoidContext:
+  if n[^1].typ == c.enforceVoidContext:
     result.typ = c.enforceVoidContext
   elif efInTypeof in flags:
     result.typ = result.lastSon.typ
@@ -897,18 +891,18 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
   checkMinSonsLen(n, 2, c.config)
   openScope(c)
   pushCaseContext(c, n)
-  n.sons[0] = semExprWithType(c, n.sons[0])
+  n[0] = semExprWithType(c, n[0])
   var chckCovered = false
   var covered: Int128 = toInt128(0)
   var typ = commonTypeBegin
   var hasElse = false
-  let caseTyp = skipTypes(n.sons[0].typ, abstractVar-{tyTypeDesc})
+  let caseTyp = skipTypes(n[0].typ, abstractVar-{tyTypeDesc})
   const shouldChckCovered = {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool}
   case caseTyp.kind
   of shouldChckCovered:
     chckCovered = true
   of tyRange:
-    if skipTypes(caseTyp.sons[0], abstractInst).kind in shouldChckCovered:
+    if skipTypes(caseTyp[0], abstractInst).kind in shouldChckCovered:
       chckCovered = true
   of tyFloat..tyFloat128, tyString, tyError:
     discard
@@ -919,11 +913,11 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
       result = handleCaseStmtMacro(c, n)
       if result != nil:
         return result
-    localError(c.config, n.sons[0].info, errSelectorMustBeOfCertainTypes)
+    localError(c.config, n[0].info, errSelectorMustBeOfCertainTypes)
     return
-  for i in 1 ..< len(n):
+  for i in 1..<n.len:
     setCaseContextIdx(c, i)
-    var x = n.sons[i]
+    var x = n[i]
     when defined(nimsuggest):
       if c.config.ideCmd == ideSug and exactEquals(c.config.m.trackPos, x.info) and caseTyp.kind == tyEnum:
         suggestEnum(c, x, caseTyp)
@@ -931,31 +925,31 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
     of nkOfBranch:
       checkMinSonsLen(x, 2, c.config)
       semCaseBranch(c, n, x, i, covered)
-      var last = len(x)-1
-      x.sons[last] = semExprBranchScope(c, x.sons[last])
-      typ = commonType(typ, x.sons[last])
+      var last = x.len-1
+      x[last] = semExprBranchScope(c, x[last])
+      typ = commonType(typ, x[last])
     of nkElifBranch:
       chckCovered = false
       checkSonsLen(x, 2, c.config)
       openScope(c)
-      x.sons[0] = forceBool(c, semExprWithType(c, x.sons[0]))
-      x.sons[1] = semExprBranch(c, x.sons[1])
-      typ = commonType(typ, x.sons[1])
+      x[0] = forceBool(c, semExprWithType(c, x[0]))
+      x[1] = semExprBranch(c, x[1])
+      typ = commonType(typ, x[1])
       closeScope(c)
     of nkElse:
       checkSonsLen(x, 1, c.config)
-      x.sons[0] = semExprBranchScope(c, x.sons[0])
-      typ = commonType(typ, x.sons[0])
+      x[0] = semExprBranchScope(c, x[0])
+      typ = commonType(typ, x[0])
       hasElse = true
-      if chckCovered and covered == toCover(c, n.sons[0].typ):
+      if chckCovered and covered == toCover(c, n[0].typ):
         localError(c.config, x.info, "invalid else, all cases are already covered")
       chckCovered = false
     else:
       illFormedAst(x, c.config)
   if chckCovered:
-    if covered == toCover(c, n.sons[0].typ):
+    if covered == toCover(c, n[0].typ):
       hasElse = true
-    elif n.sons[0].typ.kind == tyEnum:
+    elif n[0].typ.kind == tyEnum:
       localError(c.config, n.info, "not all cases are covered; missing: {$1}" %
                  formatMissingEnums(n))
     else:
@@ -964,16 +958,16 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
   closeScope(c)
   if isEmptyType(typ) or typ.kind in {tyNil, tyUntyped} or
       (not hasElse and efInTypeof notin flags):
-    for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon, flags)
+    for i in 1..<n.len: discardCheck(c, n[i].lastSon, flags)
     # propagate any enforced VoidContext:
     if typ == c.enforceVoidContext:
       result.typ = c.enforceVoidContext
   else:
-    for i in 1..n.len-1:
-      var it = n.sons[i]
+    for i in 1..<n.len:
+      var it = n[i]
       let j = it.len-1
-      if not endsInNoReturn(it.sons[j]):
-        it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info)
+      if not endsInNoReturn(it[j]):
+        it[j] = fitNode(c, typ, it[j], it[j].info)
     result.typ = typ
 
 proc semRaise(c: PContext, n: PNode): PNode =
@@ -992,15 +986,15 @@ proc semRaise(c: PContext, n: PNode): PNode =
 
 proc addGenericParamListToScope(c: PContext, n: PNode) =
   if n.kind != nkGenericParams: illFormedAst(n, c.config)
-  for i in 0 ..< len(n):
-    var a = n.sons[i]
+  for i in 0..<n.len:
+    var a = n[i]
     if a.kind == nkSym: addDecl(c, a.sym)
     else: illFormedAst(a, c.config)
 
 proc typeSectionTypeName(c: PContext; n: PNode): PNode =
   if n.kind == nkPragmaExpr:
     if n.len == 0: illFormedAst(n, c.config)
-    result = n.sons[0]
+    result = n[0]
   else:
     result = n
   if result.kind != nkSym: illFormedAst(n, c.config)
@@ -1009,8 +1003,8 @@ proc typeSectionTypeName(c: PContext; n: PNode): 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 0 ..< len(n):
-    var a = n.sons[i]
+  for i in 0..<n.len:
+    var a = n[i]
     when defined(nimsuggest):
       if c.config.cmd == cmdIdeTools:
         inc c.inTypeContext
@@ -1019,7 +1013,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
     if a.kind == nkCommentStmt: continue
     if a.kind != nkTypeDef: illFormedAst(a, c.config)
     checkSonsLen(a, 3, c.config)
-    let name = a.sons[0]
+    let name = a[0]
     var s: PSym
     if name.kind == nkDotExpr and a[2].kind == nkObjectTy:
       let pkgName = considerQuotedIdent(c, name[0])
@@ -1049,7 +1043,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
       s.typ = newTypeS(tyForward, c)
       s.typ.sym = s             # process pragmas:
       if name.kind == nkPragmaExpr:
-        pragma(c, s, name.sons[1], typePragmas)
+        pragma(c, s, name[1], typePragmas)
       if sfForward in s.flags:
         # check if the symbol already exists:
         let pkg = c.module.owner
@@ -1070,9 +1064,9 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
       elif s.owner == nil: s.owner = getCurrOwner(c)
 
     if name.kind == nkPragmaExpr:
-      a.sons[0].sons[0] = newSymNode(s)
+      a[0][0] = newSymNode(s)
     else:
-      a.sons[0] = newSymNode(s)
+      a[0] = newSymNode(s)
 
 proc checkCovariantParamsUsages(c: PContext; genericType: PType) =
   var body = genericType[^1]
@@ -1103,7 +1097,7 @@ proc checkCovariantParamsUsages(c: PContext; genericType: PType) =
       return traverseSubTypes(c, t[0])
     of tyGenericInvocation:
       let targetBody = t[0]
-      for i in 1 ..< t.len:
+      for i in 1..<t.len:
         let param = t[i]
         if param.kind == tyGenericParam:
           if tfCovariant in param.flags:
@@ -1141,17 +1135,17 @@ proc checkCovariantParamsUsages(c: PContext; genericType: PType) =
   discard traverseSubTypes(c, body)
 
 proc typeSectionRightSidePass(c: PContext, n: PNode) =
-  for i in 0 ..< len(n):
-    var a = n.sons[i]
+  for i in 0..<n.len:
+    var a = n[i]
     if a.kind == nkCommentStmt: continue
     if a.kind != nkTypeDef: illFormedAst(a, c.config)
     checkSonsLen(a, 3, c.config)
-    let name = typeSectionTypeName(c, a.sons[0])
+    let name = typeSectionTypeName(c, a[0])
     var s = name.sym
-    if s.magic == mNone and a.sons[2].kind == nkEmpty:
+    if s.magic == mNone and a[2].kind == nkEmpty:
       localError(c.config, a.info, errImplOfXexpected % s.name.s)
     if s.magic != mNone: processMagicType(c, s)
-    if a.sons[1].kind != nkEmpty:
+    if a[1].kind != nkEmpty:
       # We have a generic type declaration here. In generic types,
       # symbol lookup needs to be done here.
       openScope(c)
@@ -1164,8 +1158,8 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
       #   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.n = semGenericParamList(c, a[1], s.typ)
+      a[1] = s.typ.n
       s.typ.size = -1 # could not be computed properly
       # we fill it out later. For magic generics like 'seq', it won't be filled
       # so we use tyNone instead of nil to not crash for strange conversions
@@ -1173,12 +1167,12 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
       rawAddSon(s.typ, newTypeS(tyNone, c))
       s.ast = a
       inc c.inGenericContext
-      var body = semTypeNode(c, a.sons[2], nil)
+      var body = semTypeNode(c, a[2], nil)
       dec c.inGenericContext
       if body != nil:
         body.sym = s
         body.size = -1 # could not be computed properly
-        s.typ.sons[len(s.typ) - 1] = body
+        s.typ[^1] = body
         if tfCovariant in s.typ.flags:
           checkCovariantParamsUsages(c, s.typ)
           # XXX: This is a temporary limitation:
@@ -1200,10 +1194,10 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
 
       popOwner(c)
       closeScope(c)
-    elif a.sons[2].kind != nkEmpty:
+    elif a[2].kind != nkEmpty:
       # process the type's body:
       pushOwner(c, s)
-      var t = semTypeNode(c, a.sons[2], s.typ)
+      var t = semTypeNode(c, a[2], s.typ)
       if s.typ == nil:
         s.typ = t
       elif t != s.typ and (s.typ == nil or s.typ.kind != tyAlias):
@@ -1222,9 +1216,9 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
     if tfBorrowDot in s.typ.flags and s.typ.kind != tyDistinct:
       excl s.typ.flags, tfBorrowDot
       localError(c.config, name.info, "only a 'distinct' type can borrow `.`")
-    let aa = a.sons[2]
+    let aa = a[2]
     if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
-       aa.sons[0].kind == nkObjectTy:
+       aa[0].kind == nkObjectTy:
       # give anonymous object a dummy symbol:
       var st = s.typ
       if st.kind == tyGenericBody: st = st.lastSon
@@ -1242,7 +1236,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
 proc checkForMetaFields(c: PContext; n: PNode) =
   proc checkMeta(c: PContext; n: PNode; t: PType) =
     if t != nil and t.isMetaType and tfGenericTypeParam notin t.flags:
-      if t.kind == tyBuiltInTypeClass and t.len == 1 and t.sons[0].kind == tyProc:
+      if t.kind == tyBuiltInTypeClass and t.len == 1 and t[0].kind == tyProc:
         localError(c.config, n.info, ("'$1' is not a concrete type; " &
           "for a callback without parameters use 'proc()'") % t.typeToString)
       else:
@@ -1260,23 +1254,23 @@ proc checkForMetaFields(c: PContext; n: PNode) =
     of tySequence, tySet, tyArray, tyOpenArray, tyVar, tyLent, tyPtr, tyRef,
        tyProc, tyGenericInvocation, tyGenericInst, tyAlias, tySink, tyOwned:
       let start = ord(t.kind in {tyGenericInvocation, tyGenericInst})
-      for i in start ..< t.len:
-        checkMeta(c, n, t.sons[i])
+      for i in start..<t.len:
+        checkMeta(c, n, t[i])
     else:
       checkMeta(c, n, t)
   else:
     internalAssert c.config, false
 
 proc typeSectionFinalPass(c: PContext, n: PNode) =
-  for i in 0 ..< len(n):
-    var a = n.sons[i]
+  for i in 0..<n.len:
+    var a = n[i]
     if a.kind == nkCommentStmt: continue
-    let name = typeSectionTypeName(c, a.sons[0])
+    let name = typeSectionTypeName(c, a[0])
     var s = name.sym
     # check the style here after the pragmas have been processed:
     styleCheckDef(c.config, s)
     # compute the type's size and check for illegal recursions:
-    if a.sons[1].kind == nkEmpty:
+    if a[1].kind == nkEmpty:
       var x = a[2]
       if x.kind in nkCallKinds and nfSem in x.flags:
         discard "already semchecked, see line marked with bug #10548"
@@ -1307,7 +1301,7 @@ proc semAllTypeSections(c: PContext; n: PNode): PNode =
     case n.kind
     of nkIncludeStmt:
       for i in 0..<n.len:
-        var f = checkModuleName(c.config, n.sons[i])
+        var f = checkModuleName(c.config, n[i])
         if f != InvalidFileIdx:
           if containsOrIncl(c.includedFiles, f.int):
             localError(c.config, n.info, errRecursiveDependencyX % toMsgFilename(c.config, f))
@@ -1316,8 +1310,8 @@ proc semAllTypeSections(c: PContext; n: PNode): PNode =
             gatherStmts c, code, result
             excl(c.includedFiles, f.int)
     of nkStmtList:
-      for i in 0 ..< n.len:
-        gatherStmts(c, n.sons[i], result)
+      for i in 0..<n.len:
+        gatherStmts(c, n[i], result)
     of nkTypeSection:
       incl n.flags, nfSem
       typeSectionLeftSidePass(c, n)
@@ -1329,7 +1323,7 @@ proc semAllTypeSections(c: PContext; n: PNode): PNode =
   gatherStmts(c, n, result)
 
   template rec(name) =
-    for i in 0 ..< result.len:
+    for i in 0..<result.len:
       if result[i].kind == nkTypeSection:
         name(c, result[i])
 
@@ -1343,8 +1337,8 @@ proc semAllTypeSections(c: PContext; n: PNode): PNode =
           when setbit: incl n.flags, nfSem
           name(c, n)
         elif n.kind == nkStmtList:
-          for i in 0 ..< n.len:
-            `name rec`(c, n.sons[i])
+          for i in 0..<n.len:
+            `name rec`(c, n[i])
       `name rec`(c, n)
     rec typeSectionLeftSidePass, true
     rec typeSectionRightSidePass
@@ -1366,8 +1360,8 @@ proc semParamList(c: PContext, n, genericParams: PNode, s: PSym) =
   s.typ = semProcTypeNode(c, n, genericParams, nil, s.kind)
 
 proc addParams(c: PContext, n: PNode, kind: TSymKind) =
-  for i in 1 ..< len(n):
-    if n.sons[i].kind == nkSym: addParamOrResult(c, n.sons[i].sym, kind)
+  for i in 1..<n.len:
+    if n[i].kind == nkSym: addParamOrResult(c, n[i].sym, kind)
     else: illFormedAst(n, c.config)
 
 proc semBorrow(c: PContext, n: PNode, s: PSym) =
@@ -1375,7 +1369,7 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) =
   var b = searchForBorrowProc(c, c.currentScope.parent, s)
   if b != nil:
     # store the alias:
-    n.sons[bodyPos] = newSymNode(b)
+    n[bodyPos] = newSymNode(b)
     # Carry over the original symbol magic, this is necessary in order to ensure
     # the semantic pass is correct
     s.magic = b.magic
@@ -1391,20 +1385,20 @@ proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
     c.p.resultSym = s
 
 proc addResultNode(c: PContext, n: PNode) =
-  if c.p.resultSym != nil: addSon(n, newSymNode(c.p.resultSym))
+  if c.p.resultSym != nil: n.add newSymNode(c.p.resultSym)
 
 proc copyExcept(n: PNode, i: int): PNode =
   result = copyNode(n)
   for j in 0..<n.len:
-    if j != i: result.add(n.sons[j])
+    if j != i: result.add(n[j])
 
 proc semProcAnnotation(c: PContext, prc: PNode;
                        validPragmas: TSpecialWords): PNode =
-  var n = prc.sons[pragmasPos]
+  var n = prc[pragmasPos]
   if n == nil or n.kind == nkEmpty: return
-  for i in 0 ..< n.len:
-    var it = n.sons[i]
-    var key = if it.kind in nkPragmaCallKinds and it.len >= 1: it.sons[0] else: it
+  for i in 0..<n.len:
+    var it = n[i]
+    var key = if it.kind in nkPragmaCallKinds and it.len >= 1: it[0] else: it
 
     if whichPragma(it) != wInvalid:
       # Not a custom pragma
@@ -1421,13 +1415,13 @@ proc semProcAnnotation(c: PContext, prc: PNode;
     if it.kind in nkPragmaCallKinds and it.len > 1:
       # pass pragma arguments to the macro too:
       for i in 1..<it.len:
-        x.add(it.sons[i])
+        x.add(it[i])
 
     # Drop the pragma from the list, this prevents getting caught in endless
     # recursion when the nkCall is semanticized
-    prc.sons[pragmasPos] = copyExcept(n, i)
+    prc[pragmasPos] = copyExcept(n, i)
     if prc[pragmasPos].kind != nkEmpty and prc[pragmasPos].len == 0:
-      prc.sons[pragmasPos] = c.graph.emptyNode
+      prc[pragmasPos] = c.graph.emptyNode
 
     x.add(prc)
 
@@ -1435,18 +1429,18 @@ proc semProcAnnotation(c: PContext, prc: PNode;
     var r = semOverloadedCall(c, x, x, {skMacro, skTemplate}, {efNoUndeclared})
     if r == nil:
       # Restore the old list of pragmas since we couldn't process this
-      prc.sons[pragmasPos] = n
+      prc[pragmasPos] = n
       # No matching macro was found but there's always the possibility this may
       # be a .pragma. template instead
       continue
 
-    doAssert r.sons[0].kind == nkSym
-    let m = r.sons[0].sym
+    doAssert r[0].kind == nkSym
+    let m = r[0].sym
     case m.kind
     of skMacro: result = semMacroExpr(c, r, r, m, {})
     of skTemplate: result = semTemplateExpr(c, r, m, {})
     else:
-      prc.sons[pragmasPos] = n
+      prc[pragmasPos] = n
       continue
 
     doAssert result != nil
@@ -1460,15 +1454,15 @@ proc semProcAnnotation(c: PContext, prc: PNode;
     return
 
 proc setGenericParamsMisc(c: PContext; n: PNode): PNode =
-  let orig = n.sons[genericParamsPos]
+  let orig = n[genericParamsPos]
   # we keep the original params around for better error messages, see
   # issue https://github.com/nim-lang/Nim/issues/1713
   result = semGenericParamList(c, orig)
-  if n.sons[miscPos].kind == nkEmpty:
-    n.sons[miscPos] = newTree(nkBracket, c.graph.emptyNode, orig)
+  if n[miscPos].kind == nkEmpty:
+    n[miscPos] = newTree(nkBracket, c.graph.emptyNode, orig)
   else:
-    n.sons[miscPos].sons[1] = orig
-  n.sons[genericParamsPos] = result
+    n[miscPos][1] = orig
+  n[genericParamsPos] = result
 
 proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
   # XXX semProcAux should be good enough for this now, we will eventually
@@ -1481,38 +1475,38 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
   if n[namePos].kind != nkSym:
     s = newSym(skProc, c.cache.idAnon, getCurrOwner(c), n.info)
     s.ast = n
-    n.sons[namePos] = newSymNode(s)
+    n[namePos] = newSymNode(s)
   else:
     s = n[namePos].sym
   pushOwner(c, s)
   openScope(c)
   var gp: PNode
-  if n.sons[genericParamsPos].kind != nkEmpty:
+  if n[genericParamsPos].kind != nkEmpty:
     gp = setGenericParamsMisc(c, n)
   else:
     gp = newNodeI(nkGenericParams, n.info)
 
-  if n.sons[paramsPos].kind != nkEmpty:
-    semParamList(c, n.sons[paramsPos], gp, s)
+  if n[paramsPos].kind != nkEmpty:
+    semParamList(c, n[paramsPos], gp, s)
     # paramsTypeCheck(c, s.typ)
-    if len(gp) > 0 and n.sons[genericParamsPos].kind == nkEmpty:
+    if gp.len > 0 and n[genericParamsPos].kind == nkEmpty:
       # we have a list of implicit type parameters:
-      n.sons[genericParamsPos] = gp
+      n[genericParamsPos] = gp
   else:
     s.typ = newProcType(c, n.info)
-  if n.sons[pragmasPos].kind != nkEmpty:
-    pragma(c, s, n.sons[pragmasPos], lambdaPragmas)
+  if n[pragmasPos].kind != nkEmpty:
+    pragma(c, s, n[pragmasPos], lambdaPragmas)
   s.options = c.config.options
-  if n.sons[bodyPos].kind != nkEmpty:
+  if n[bodyPos].kind != nkEmpty:
     if sfImportc in s.flags:
-      localError(c.config, n.sons[bodyPos].info, errImplOfXNotAllowed % s.name.s)
+      localError(c.config, n[bodyPos].info, errImplOfXNotAllowed % s.name.s)
     #if efDetermineType notin flags:
     # XXX not good enough; see tnamedparamanonproc.nim
     if gp.len == 0 or (gp.len == 1 and tfRetType in gp[0].typ.flags):
       pushProcCon(c, s)
-      addResult(c, s.typ.sons[0], n.info, skProc)
+      addResult(c, s.typ[0], n.info, skProc)
       addResultNode(c, n)
-      s.ast[bodyPos] = hloBody(c, semProcBody(c, n.sons[bodyPos]))
+      s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos]))
       trackProc(c, s, s.ast[bodyPos])
       popProcCon(c)
     elif efOperand notin flags:
@@ -1529,7 +1523,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
 proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
   var n = n
 
-  let original = n.sons[namePos].sym
+  let original = n[namePos].sym
   let s = original #copySym(original, false)
   #incl(s.flags, sfFromGeneric)
   #s.owner = original
@@ -1537,11 +1531,11 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
   n = replaceTypesInBody(c, pt, n, original)
   result = n
   s.ast = result
-  n.sons[namePos].sym = s
-  n.sons[genericParamsPos] = c.graph.emptyNode
+  n[namePos].sym = s
+  n[genericParamsPos] = c.graph.emptyNode
   # for LL we need to avoid wrong aliasing
   let params = copyTree n.typ.n
-  n.sons[paramsPos] = params
+  n[paramsPos] = params
   s.typ = n.typ
   for i in 1..<params.len:
     if params[i].typ.kind in {tyTypeDesc, tyGenericParam,
@@ -1553,9 +1547,9 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
   pushOwner(c, s)
   addParams(c, params, skProc)
   pushProcCon(c, s)
-  addResult(c, n.typ.sons[0], n.info, skProc)
+  addResult(c, n.typ[0], n.info, skProc)
   addResultNode(c, n)
-  s.ast[bodyPos] = hloBody(c, semProcBody(c, n.sons[bodyPos]))
+  s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos]))
   trackProc(c, s, s.ast[bodyPos])
   popProcCon(c)
   popOwner(c)
@@ -1577,7 +1571,7 @@ proc activate(c: PContext, n: PNode) =
     of nkLambdaKinds:
       discard semLambda(c, n, {})
     of nkCallKinds:
-      for i in 1 ..< n.len: activate(c, n[i])
+      for i in 1..<n.len: activate(c, n[i])
     else:
       discard
 
@@ -1586,8 +1580,8 @@ proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
     let resultType = sysTypeFromName(c.graph, n.info, "NimNode")
     addResult(c, resultType, n.info, s.kind)
     addResultNode(c, n)
-  elif s.typ.sons[0] != nil and not isInlineIterator(s.typ):
-    addResult(c, s.typ.sons[0], n.info, s.kind)
+  elif s.typ[0] != nil and not isInlineIterator(s.typ):
+    addResult(c, s.typ[0], n.info, s.kind)
     addResultNode(c, n)
 
 proc canonType(c: PContext, t: PType): PType =
@@ -1610,12 +1604,12 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
   of "=destroy":
     let t = s.typ
     var noError = false
-    if t.len == 2 and t.sons[0] == nil and t.sons[1].kind == tyVar:
-      var obj = t.sons[1].sons[0]
+    if t.len == 2 and t[0] == nil and t[1].kind == tyVar:
+      var obj = t[1][0]
       while true:
         incl(obj.flags, tfHasAsgn)
         if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.lastSon
-        elif obj.kind == tyGenericInvocation: obj = obj.sons[0]
+        elif obj.kind == tyGenericInvocation: obj = obj[0]
         else: break
       if obj.kind in {tyObject, tyDistinct, tySequence, tyString}:
         obj = canonType(c, obj)
@@ -1636,14 +1630,14 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
     incl(s.flags, sfOverriden)
   of "deepcopy", "=deepcopy":
     if s.typ.len == 2 and
-        s.typ.sons[1].skipTypes(abstractInst).kind in {tyRef, tyPtr} and
-        sameType(s.typ.sons[1], s.typ.sons[0]):
+        s.typ[1].skipTypes(abstractInst).kind in {tyRef, tyPtr} and
+        sameType(s.typ[1], s.typ[0]):
       # Note: we store the deepCopy in the base of the pointer to mitigate
       # the problem that pointers are structural types:
-      var t = s.typ.sons[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst)
+      var t = s.typ[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst)
       while true:
         if t.kind == tyGenericBody: t = t.lastSon
-        elif t.kind == tyGenericInvocation: t = t.sons[0]
+        elif t.kind == tyGenericInvocation: t = t[0]
         else: break
       if t.kind in {tyObject, tyDistinct, tyEnum, tySequence, tyString}:
         if t.attachedOps[attachedDeepCopy].isNil: t.attachedOps[attachedDeepCopy] = s
@@ -1668,18 +1662,18 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
     incl(s.flags, sfUsed)
     incl(s.flags, sfOverriden)
     let t = s.typ
-    if t.len == 3 and t.sons[0] == nil and t.sons[1].kind == tyVar:
-      var obj = t.sons[1].sons[0]
+    if t.len == 3 and t[0] == nil and t[1].kind == tyVar:
+      var obj = t[1][0]
       while true:
         incl(obj.flags, tfHasAsgn)
         if obj.kind == tyGenericBody: obj = obj.lastSon
-        elif obj.kind == tyGenericInvocation: obj = obj.sons[0]
+        elif obj.kind == tyGenericInvocation: obj = obj[0]
         else: break
-      var objB = t.sons[2]
+      var objB = t[2]
       while true:
         if objB.kind == tyGenericBody: objB = objB.lastSon
         elif objB.kind in {tyGenericInvocation, tyGenericInst}:
-          objB = objB.sons[0]
+          objB = objB[0]
         else: break
       if obj.kind in {tyObject, tyDistinct, tySequence, tyString} and sameType(obj, objB):
         # attach these ops to the canonical tySequence
@@ -1721,8 +1715,8 @@ type
 
 proc hasObjParam(s: PSym): bool =
   var t = s.typ
-  for col in 1 ..< len(t):
-    if skipTypes(t.sons[col], skipPtrs).kind == tyObject:
+  for col in 1..<t.len:
+    if skipTypes(t[col], skipPtrs).kind == tyObject:
       return true
 
 proc finishMethod(c: PContext, s: PSym) =
@@ -1735,13 +1729,13 @@ proc semMethodPrototype(c: PContext; s: PSym; n: PNode) =
     var foundObj = false
     # we start at 1 for now so that tparsecombnum continues to compile.
     # XXX Revisit this problem later.
-    for col in 1 ..< len(tt):
-      let t = tt.sons[col]
+    for col in 1..<tt.len:
+      let t = tt[col]
       if t != nil and t.kind == tyGenericInvocation:
-        var x = skipTypes(t.sons[0], {tyVar, tyLent, tyPtr, tyRef, tyGenericInst,
+        var x = skipTypes(t[0], {tyVar, tyLent, tyPtr, tyRef, tyGenericInst,
                                       tyGenericInvocation, tyGenericBody,
                                       tyAlias, tySink, tyOwned})
-        if x.kind == tyObject and t.len-1 == n.sons[genericParamsPos].len:
+        if x.kind == tyObject and t.len-1 == n[genericParamsPos].len:
           foundObj = true
           x.methods.add((col,s))
     message(c.config, n.info, warnDeprecated, "generic methods are deprecated")
@@ -1750,7 +1744,7 @@ proc semMethodPrototype(c: PContext; s: PSym; n: PNode) =
   else:
     # why check for the body? bug #2400 has none. Checking for sfForward makes
     # no sense either.
-    # and result.sons[bodyPos].kind != nkEmpty:
+    # and result[bodyPos].kind != nkEmpty:
     if hasObjParam(s):
       methodDef(c.graph, s, fromCache=false)
     else:
@@ -1774,8 +1768,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
       incl(s.flags, sfUsed)
       isAnon = true
     else:
-      s = semIdentDef(c, n.sons[0], kind)
-    n.sons[namePos] = newSymNode(s)
+      s = semIdentDef(c, n[0], kind)
+    n[namePos] = newSymNode(s)
     s.ast = n
     #s.scope = c.currentScope
     when false:
@@ -1801,24 +1795,24 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
   pushOwner(c, s)
   openScope(c)
   var gp: PNode
-  if n.sons[genericParamsPos].kind != nkEmpty:
+  if n[genericParamsPos].kind != nkEmpty:
     gp = setGenericParamsMisc(c, n)
   else:
     gp = newNodeI(nkGenericParams, n.info)
   # process parameters:
-  if n.sons[paramsPos].kind != nkEmpty:
-    semParamList(c, n.sons[paramsPos], gp, s)
-    if len(gp) > 0:
-      if n.sons[genericParamsPos].kind == nkEmpty:
+  if n[paramsPos].kind != nkEmpty:
+    semParamList(c, n[paramsPos], gp, s)
+    if gp.len > 0:
+      if n[genericParamsPos].kind == nkEmpty:
         # we have a list of implicit type parameters:
-        n.sons[genericParamsPos] = gp
+        n[genericParamsPos] = gp
         # check for semantics again:
-        # semParamList(c, n.sons[ParamsPos], nil, s)
+        # semParamList(c, n[ParamsPos], nil, s)
   else:
     s.typ = newProcType(c, n.info)
   if tfTriggersCompileTime in s.typ.flags: incl(s.flags, sfCompileTime)
-  if n.sons[patternPos].kind != nkEmpty:
-    n.sons[patternPos] = semPattern(c, n.sons[patternPos])
+  if n[patternPos].kind != nkEmpty:
+    n[patternPos] = semPattern(c, n[patternPos])
   if s.kind == skIterator:
     s.typ.flags.incl(tfIterator)
   elif s.kind == skFunc:
@@ -1841,15 +1835,15 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     else:
       if not typeIsDetermined:
         addInterfaceDeclAt(c, oldScope, s)
-    if n.sons[pragmasPos].kind != nkEmpty:
-      pragma(c, s, n.sons[pragmasPos], validPragmas)
+    if n[pragmasPos].kind != nkEmpty:
+      pragma(c, s, n[pragmasPos], validPragmas)
     else:
       implicitPragmas(c, s, n, validPragmas)
     styleCheckDef(c.config, s)
     onDef(n[namePos].info, s)
   else:
-    if n.sons[pragmasPos].kind != nkEmpty:
-      pragma(c, s, n.sons[pragmasPos], validPragmas)
+    if n[pragmasPos].kind != nkEmpty:
+      pragma(c, s, n[pragmasPos], validPragmas)
       # To ease macro generation that produce forwarded .async procs we now
       # allow a bit redudancy in the pragma declarations. The rule is
       # a prototype's pragma list must be a superset of the current pragma
@@ -1857,7 +1851,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
       # XXX This needs more checks eventually, for example that external
       # linking names do agree:
       if proto.typ.callConv != s.typ.callConv or proto.typ.flags < s.typ.flags:
-        localError(c.config, n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX %
+        localError(c.config, n[pragmasPos].info, errPragmaOnlyInHeaderOfProcX %
           ("'" & proto.name.s & "' from " & c.config$proto.info))
     styleCheckDef(c.config, s)
     onDefResolveForward(n[namePos].info, proto)
@@ -1866,18 +1860,18 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     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:
-      addGenericParamListToScope(c, proto.ast.sons[genericParamsPos])
+    if proto.ast[genericParamsPos].kind != nkEmpty:
+      addGenericParamListToScope(c, proto.ast[genericParamsPos])
     addParams(c, proto.typ.n, proto.kind)
     proto.info = s.info       # more accurate line information
     s.typ = proto.typ
     proto.options = s.options
     s = proto
-    n.sons[genericParamsPos] = proto.ast.sons[genericParamsPos]
-    n.sons[paramsPos] = proto.ast.sons[paramsPos]
-    n.sons[pragmasPos] = proto.ast.sons[pragmasPos]
-    if n.sons[namePos].kind != nkSym: internalError(c.config, n.info, "semProcAux")
-    n.sons[namePos].sym = proto
+    n[genericParamsPos] = proto.ast[genericParamsPos]
+    n[paramsPos] = proto.ast[paramsPos]
+    n[pragmasPos] = proto.ast[pragmasPos]
+    if n[namePos].kind != nkSym: internalError(c.config, n.info, "semProcAux")
+    n[namePos].sym = proto
     if importantComments(c.config) and proto.ast.comment.len > 0:
       n.comment = proto.ast.comment
     proto.ast = n             # needed for code generation
@@ -1893,44 +1887,44 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
       localError(c.config, n.info, "the overloaded " & s.name.s &
         " operator has to be enabled with {.experimental: \"callOperator\".}")
 
-  if n.sons[bodyPos].kind != nkEmpty and sfError notin s.flags:
+  if n[bodyPos].kind != nkEmpty and sfError notin s.flags:
     # for DLL generation we allow sfImportc to have a body, for use in VM
     if sfBorrow in s.flags:
-      localError(c.config, n.sons[bodyPos].info, errImplOfXNotAllowed % s.name.s)
+      localError(c.config, n[bodyPos].info, errImplOfXNotAllowed % s.name.s)
     let usePseudoGenerics = kind in {skMacro, skTemplate}
     # Macros and Templates can have generic parameters, but they are
     # only used for overload resolution (there is no instantiation of
     # the symbol, so we must process the body now)
     if not usePseudoGenerics and c.config.ideCmd in {ideSug, ideCon} and not
-        cursorInProc(c.config, n.sons[bodyPos]):
+        cursorInProc(c.config, n[bodyPos]):
       discard "speed up nimsuggest"
       if s.kind == skMethod: semMethodPrototype(c, s, n)
     else:
       pushProcCon(c, s)
-      if n.sons[genericParamsPos].kind == nkEmpty or usePseudoGenerics:
+      if n[genericParamsPos].kind == nkEmpty or usePseudoGenerics:
         if not usePseudoGenerics and s.magic == mNone: paramsTypeCheck(c, s.typ)
 
         c.p.wasForwarded = proto != nil
         maybeAddResult(c, s, n)
         # semantic checking also needed with importc in case used in VM
-        s.ast[bodyPos] = hloBody(c, semProcBody(c, n.sons[bodyPos]))
+        s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos]))
         # unfortunately we cannot skip this step when in 'system.compiles'
         # context as it may even be evaluated in 'system.compiles':
         trackProc(c, s, s.ast[bodyPos])
         if s.kind == skMethod: semMethodPrototype(c, s, n)
       else:
-        if (s.typ.sons[0] != nil and kind != skIterator) or kind == skMacro:
+        if (s.typ[0] != nil and kind != skIterator) or kind == skMacro:
           addDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nil, n.info))
 
         openScope(c)
-        n.sons[bodyPos] = semGenericStmt(c, n.sons[bodyPos])
+        n[bodyPos] = semGenericStmt(c, n[bodyPos])
         closeScope(c)
         if s.magic == mNone:
           fixupInstantiatedSymbols(c, s)
         if s.kind == skMethod: semMethodPrototype(c, s, n)
       if sfImportc in s.flags:
         # don't ignore the body in case used in VM
-        # n.sons[bodyPos] = c.graph.emptyNode
+        # n[bodyPos] = c.graph.emptyNode
         discard
       popProcCon(c)
   else:
@@ -1947,7 +1941,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
   closeScope(c)           # close scope for parameters
   # c.currentScope = oldScope
   popOwner(c)
-  if n.sons[patternPos].kind != nkEmpty:
+  if n[patternPos].kind != nkEmpty:
     c.patterns.add(s)
   if isAnon:
     n.kind = nkLambda
@@ -1975,9 +1969,9 @@ proc semIterator(c: PContext, n: PNode): PNode =
   # nkIteratorDef aynmore, return. The iterator then might have been
   # sem'checked already. (Or not, if the macro skips it.)
   if result.kind != n.kind: return
-  var s = result.sons[namePos].sym
+  var s = result[namePos].sym
   var t = s.typ
-  if t.sons[0] == nil and s.typ.callConv != ccClosure:
+  if t[0] == nil and s.typ.callConv != ccClosure:
     localError(c.config, n.info, "iterator needs a return type")
   # iterators are either 'inline' or 'closure'; for backwards compatibility,
   # we require first class iterators to be marked with 'closure' explicitly
@@ -1986,7 +1980,7 @@ proc semIterator(c: PContext, n: PNode): PNode =
     incl(s.typ.flags, tfCapturesEnv)
   else:
     s.typ.callConv = ccInline
-  if n.sons[bodyPos].kind == nkEmpty and s.magic == mNone:
+  if n[bodyPos].kind == nkEmpty and s.magic == mNone:
     localError(c.config, n.info, errImplOfXexpected % s.name.s)
   if optOwnedRefs in c.config.globalOptions and result.typ != nil:
     result.typ = makeVarType(c, result.typ, tyOwned)
@@ -2007,16 +2001,16 @@ proc semMethod(c: PContext, n: PNode): PNode =
   # nkIteratorDef aynmore, return. The iterator then might have been
   # sem'checked already. (Or not, if the macro skips it.)
   if result.kind != nkMethodDef: return
-  var s = result.sons[namePos].sym
+  var s = result[namePos].sym
   # we need to fix the 'auto' return type for the dispatcher here (see tautonotgeneric
   # test case):
   let disp = getDispatcher(s)
   # auto return type?
-  if disp != nil and disp.typ.sons[0] != nil and disp.typ.sons[0].kind == tyUntyped:
-    let ret = s.typ.sons[0]
-    disp.typ.sons[0] = ret
+  if disp != nil and disp.typ[0] != nil and disp.typ[0].kind == tyUntyped:
+    let ret = s.typ[0]
+    disp.typ[0] = ret
     if disp.ast[resultPos].kind == nkSym:
-      if isEmptyType(ret): disp.ast.sons[resultPos] = c.graph.emptyNode
+      if isEmptyType(ret): disp.ast[resultPos] = c.graph.emptyNode
       else: disp.ast[resultPos].sym.typ = ret
 
 proc semConverterDef(c: PContext, n: PNode): PNode =
@@ -2029,10 +2023,10 @@ proc semConverterDef(c: PContext, n: PNode): PNode =
   # nkIteratorDef aynmore, return. The iterator then might have been
   # sem'checked already. (Or not, if the macro skips it.)
   if result.kind != nkConverterDef: return
-  var s = result.sons[namePos].sym
+  var s = result[namePos].sym
   var t = s.typ
-  if t.sons[0] == nil: localError(c.config, n.info, errXNeedsReturnType % "converter")
-  if len(t) != 2: localError(c.config, n.info, "a converter takes exactly one argument")
+  if t[0] == nil: localError(c.config, n.info, errXNeedsReturnType % "converter")
+  if t.len != 2: localError(c.config, n.info, "a converter takes exactly one argument")
   addConverter(c, s)
 
 proc semMacroDef(c: PContext, n: PNode): PNode =
@@ -2044,14 +2038,14 @@ proc semMacroDef(c: PContext, n: PNode): PNode =
   # nkIteratorDef aynmore, return. The iterator then might have been
   # sem'checked already. (Or not, if the macro skips it.)
   if result.kind != nkMacroDef: return
-  var s = result.sons[namePos].sym
+  var s = result[namePos].sym
   var t = s.typ
   var allUntyped = true
-  for i in 1 .. t.n.len-1:
-    let param = t.n.sons[i].sym
+  for i in 1..<t.n.len:
+    let param = t.n[i].sym
     if param.typ.kind != tyUntyped: allUntyped = false
   if allUntyped: incl(s.flags, sfAllUntyped)
-  if n.sons[bodyPos].kind == nkEmpty:
+  if n[bodyPos].kind == nkEmpty:
     localError(c.config, n.info, errImplOfXexpected % s.name.s)
 
 proc incMod(c: PContext, n: PNode, it: PNode, includeStmtResult: PNode) =
@@ -2060,15 +2054,15 @@ proc incMod(c: PContext, n: PNode, it: PNode, includeStmtResult: PNode) =
     if containsOrIncl(c.includedFiles, f.int):
       localError(c.config, n.info, errRecursiveDependencyX % toMsgFilename(c.config, f))
     else:
-      addSon(includeStmtResult, semStmt(c, c.graph.includeFileCallback(c.graph, c.module, f), {}))
+      includeStmtResult.add semStmt(c, c.graph.includeFileCallback(c.graph, c.module, f), {})
       excl(c.includedFiles, f.int)
 
 proc evalInclude(c: PContext, n: PNode): PNode =
   result = newNodeI(nkStmtList, n.info)
-  addSon(result, n)
-  for i in 0 ..< len(n):
+  result.add n
+  for i in 0..<n.len:
     var imp: PNode
-    let it = n.sons[i]
+    let it = n[i]
     if it.kind == nkInfix and it.len == 3 and it[0].ident.s != "/":
       localError(c.config, it.info, "Cannot use '" & it[0].ident.s & "' in 'include'.")
     if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket:
@@ -2079,25 +2073,25 @@ proc evalInclude(c: PContext, n: PNode): PNode =
       imp.add dir
       imp.add sep # dummy entry, replaced in the loop
       for x in it[2]:
-        imp.sons[2] = x
+        imp[2] = x
         incMod(c, n, imp, result)
     else:
       incMod(c, n, it, result)
 
 proc setLine(n: PNode, info: TLineInfo) =
-  for i in 0 ..< safeLen(n): setLine(n.sons[i], info)
+  for i in 0..<n.safeLen: setLine(n[i], info)
   n.info = info
 
 proc semPragmaBlock(c: PContext, n: PNode): PNode =
   checkSonsLen(n, 2, c.config)
-  let pragmaList = n.sons[0]
+  let pragmaList = n[0]
   pragma(c, nil, pragmaList, exprPragmas)
   n[1] = semExpr(c, n[1])
   result = n
   result.typ = n[1].typ
-  for i in 0 ..< pragmaList.len:
-    case whichPragma(pragmaList.sons[i])
-    of wLine: setLine(result, pragmaList.sons[i].info)
+  for i in 0..<pragmaList.len:
+    case whichPragma(pragmaList[i])
+    of wLine: setLine(result, pragmaList[i].info)
     of wNoRewrite: incl(result.flags, nfNoRewrite)
     else: discard
 
@@ -2106,17 +2100,17 @@ proc semStaticStmt(c: PContext, n: PNode): PNode =
   #writeStackTrace()
   inc c.inStaticContext
   openScope(c)
-  let a = semStmt(c, n.sons[0], {})
+  let a = semStmt(c, n[0], {})
   closeScope(c)
   dec c.inStaticContext
-  n.sons[0] = a
+  n[0] = a
   evalStaticStmt(c.module, c.graph, a, c.p.owner)
   when false:
     # for incremental replays, keep the AST as required for replays:
     result = n
   else:
     result = newNodeI(nkDiscardStmt, n.info, 1)
-    result.sons[0] = c.graph.emptyNode
+    result[0] = c.graph.emptyNode
 
 proc usesResult(n: PNode): bool =
   # nkStmtList(expr) properly propagates the void context,
@@ -2147,19 +2141,18 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
     LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt}
   result = n
   result.kind = nkStmtList
-  var length = len(n)
   var voidContext = false
-  var last = length-1
+  var last = n.len-1
   # by not allowing for nkCommentStmt etc. we ensure nkStmtListExpr actually
   # really *ends* in the expression that produces the type: The compiler now
   # relies on this fact and it's too much effort to change that. And arguably
   #  'R(); #comment' shouldn't produce R's type anyway.
-  #while last > 0 and n.sons[last].kind in {nkPragma, nkCommentStmt,
+  #while last > 0 and n[last].kind in {nkPragma, nkCommentStmt,
   #                                         nkNilLit, nkEmpty}:
   #  dec last
-  for i in 0 ..< length:
-    var expr = semExpr(c, n.sons[i], flags)
-    n.sons[i] = expr
+  for i in 0..<n.len:
+    var expr = semExpr(c, n[i], flags)
+    n[i] = expr
     if c.matchedConcept != nil and expr.typ != nil and
         (nfFromTemplate notin n.flags or i != last):
       case expr.typ.kind
@@ -2179,25 +2172,25 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
           localError(c.config, result.info, "concept predicate failed")
       of tyUnknown: continue
       else: discard
-    if n.sons[i].typ == c.enforceVoidContext: #or usesResult(n.sons[i]):
+    if n[i].typ == c.enforceVoidContext: #or usesResult(n[i]):
       voidContext = true
       n.typ = c.enforceVoidContext
-    if i == last and (length == 1 or ({efWantValue, efInTypeof} * flags != {})):
-      n.typ = n.sons[i].typ
+    if i == last and (n.len == 1 or ({efWantValue, efInTypeof} * flags != {})):
+      n.typ = n[i].typ
       if not isEmptyType(n.typ): n.kind = nkStmtListExpr
     elif i != last or voidContext:
-      discardCheck(c, n.sons[i], flags)
+      discardCheck(c, n[i], flags)
     else:
-      n.typ = n.sons[i].typ
+      n.typ = n[i].typ
       if not isEmptyType(n.typ): n.kind = nkStmtListExpr
-    if n.sons[i].kind in LastBlockStmts or
-        n.sons[i].kind in nkCallKinds and n.sons[i][0].kind == nkSym and
-        sfNoReturn in n.sons[i][0].sym.flags:
-      for j in i + 1 ..< length:
-        case n.sons[j].kind
+    if n[i].kind in LastBlockStmts or
+        n[i].kind in nkCallKinds and n[i][0].kind == nkSym and
+        sfNoReturn in n[i][0].sym.flags:
+      for j in i + 1..<n.len:
+        case n[j].kind
         of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkBlockExpr,
             nkBlockStmt, nkState: discard
-        else: localError(c.config, n.sons[j].info,
+        else: localError(c.config, n[j].info,
           "unreachable statement after 'return' statement or '{.noReturn.}' proc")
     else: discard
 
@@ -2207,8 +2200,8 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
      # also, don't make life complicated for macros.
      # they will always expect a proper stmtlist:
      nfBlockArg notin n.flags and
-     result.sons[0].kind != nkDefer:
-    result = result.sons[0]
+     result[0].kind != nkDefer:
+    result = result[0]
 
   when defined(nimfix):
     if result.kind == nkCommentStmt and not result.comment.isNil and
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 0b1be5abf..853bc3da7 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -34,9 +34,9 @@ type
     spNone, spGenSym, spInject
 
 proc symBinding(n: PNode): TSymBinding =
-  for i in 0 ..< len(n):
-    var it = n.sons[i]
-    var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
+  for i in 0..<n.len:
+    var it = n[i]
+    var key = if it.kind == nkExprColonExpr: it[0] else: it
     if key.kind == nkIdent:
       case whichKeyword(key.ident)
       of wGensym: return spGenSym
@@ -81,13 +81,13 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule;
       if a.kind != skModule and (not isField or sfGenSym notin s.flags):
         incl(a.flags, sfUsed)
         markOwnerModuleAsUsed(c, a)
-        addSon(result, newSymNode(a, info))
+        result.add newSymNode(a, info)
         onUse(info, a)
       a = nextOverloadIter(o, c, n)
 
 proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
-  for i in 0 ..< n.len:
-    var a = n.sons[i]
+  for i in 0..<n.len:
+    var a = n[i]
     # If 'a' is an overloaded symbol, we used to use the first symbol
     # as a 'witness' and use the fact that subsequent lookups will yield
     # the same symbol!
@@ -106,14 +106,14 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
   result = newNodeI(nkEmpty, n.info)
 
 proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode =
-  for i in 0 ..< n.len:
-    toMixin.incl(considerQuotedIdent(c, n.sons[i]).id)
+  for i in 0..<n.len:
+    toMixin.incl(considerQuotedIdent(c, n[i]).id)
   result = newNodeI(nkEmpty, n.info)
 
 proc replaceIdentBySym(c: PContext; n: var PNode, s: PNode) =
   case n.kind
-  of nkPostfix: replaceIdentBySym(c, n.sons[1], s)
-  of nkPragmaExpr: replaceIdentBySym(c, n.sons[0], s)
+  of nkPostfix: replaceIdentBySym(c, n[1], s)
+  of nkPragmaExpr: replaceIdentBySym(c, n[0], s)
   of nkIdent, nkAccQuoted, nkSym: n = s
   else: illFormedAst(n, c.config)
 
@@ -132,8 +132,8 @@ template withBracketExpr(ctx, x, body: untyped) =
 
 proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
   case n.kind
-  of nkPostfix: result = getIdentNode(c, n.sons[1])
-  of nkPragmaExpr: result = getIdentNode(c, n.sons[0])
+  of nkPostfix: result = getIdentNode(c, n[1])
+  of nkPragmaExpr: result = getIdentNode(c, n[0])
   of nkIdent:
     result = n
     let s = qualifiedLookUp(c.c, n, {})
@@ -175,8 +175,8 @@ proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode =
         result = newSymNode(s, n.info)
         onUse(n.info, s)
   else:
-    for i in 0 ..< n.safeLen:
-      result.sons[i] = onlyReplaceParams(c, n.sons[i])
+    for i in 0..<n.safeLen:
+      result[i] = onlyReplaceParams(c, n[i])
 
 proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym =
   result = newSym(kind, considerQuotedIdent(c.c, n), c.owner, n.info)
@@ -185,7 +185,7 @@ proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym =
 
 proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
   # locals default to 'gensym':
-  if n.kind == nkPragmaExpr and symBinding(n.sons[1]) == spInject:
+  if n.kind == nkPragmaExpr and symBinding(n[1]) == spInject:
     # even if injected, don't produce a sym choice here:
     #n = semTemplBody(c, n)
     var x = n[0]
@@ -207,11 +207,11 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
     else:
       replaceIdentBySym(c.c, n, ident)
   else:
-    if (n.kind == nkPragmaExpr and len(n) >= 2 and n.sons[1].kind == nkPragma):
-      let pragmaNode = n.sons[1]
-      for i in 0..<pragmaNode.sons.len:
+    if (n.kind == nkPragmaExpr and n.len >= 2 and n[1].kind == nkPragma):
+      let pragmaNode = n[1]
+      for i in 0..<pragmaNode.len:
         openScope(c)
-        pragmaNode.sons[i] = semTemplBody(c,pragmaNode.sons[i])
+        pragmaNode[i] = semTemplBody(c,pragmaNode[i])
         closeScope(c)
     let ident = getIdentNode(c, n)
     if not isTemplParam(c, ident):
@@ -272,41 +272,41 @@ proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
         result = newSymNode(s, n.info)
         onUse(n.info, s)
   else:
-    for i in 0 ..< safeLen(n):
-      result.sons[i] = semRoutineInTemplName(c, n.sons[i])
+    for i in 0..<n.safeLen:
+      result[i] = semRoutineInTemplName(c, n[i])
 
 proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
   result = n
   checkSonsLen(n, bodyPos + 1, c.c.config)
   # routines default to 'inject':
-  if n.kind notin nkLambdaKinds and symBinding(n.sons[pragmasPos]) == spGenSym:
-    let ident = getIdentNode(c, n.sons[namePos])
+  if n.kind notin nkLambdaKinds and symBinding(n[pragmasPos]) == spGenSym:
+    let ident = getIdentNode(c, n[namePos])
     if not isTemplParam(c, ident):
       var s = newGenSym(k, ident, c)
       s.ast = n
       addPrelimDecl(c.c, s)
       styleCheckDef(c.c.config, n.info, s)
       onDef(n.info, s)
-      n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
+      n[namePos] = newSymNode(s, n[namePos].info)
     else:
-      n.sons[namePos] = ident
+      n[namePos] = ident
   else:
-    n.sons[namePos] = semRoutineInTemplName(c, n.sons[namePos])
+    n[namePos] = semRoutineInTemplName(c, n[namePos])
   # open scope for parameters
   openScope(c)
   for i in patternPos..paramsPos-1:
-    n.sons[i] = semTemplBody(c, n.sons[i])
+    n[i] = semTemplBody(c, n[i])
 
   if k == skTemplate: inc(c.inTemplateHeader)
-  n.sons[paramsPos] = semTemplBody(c, n.sons[paramsPos])
+  n[paramsPos] = semTemplBody(c, n[paramsPos])
   if k == skTemplate: dec(c.inTemplateHeader)
 
   for i in paramsPos+1..miscPos:
-    n.sons[i] = semTemplBody(c, n.sons[i])
+    n[i] = semTemplBody(c, n[i])
   # open scope for locals
   inc c.scopeN
   openScope(c)
-  n.sons[bodyPos] = semTemplBody(c, n.sons[bodyPos])
+  n[bodyPos] = semTemplBody(c, n[bodyPos])
   # close scope for locals
   closeScope(c)
   dec c.scopeN
@@ -314,27 +314,26 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
   closeScope(c)
 
 proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind; start=0) =
-  for i in start ..< len(n):
-    var a = n.sons[i]
+  for i in start..<n.len:
+    var a = n[i]
     if a.kind == nkCommentStmt: continue
     if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a, c.c.config)
     checkMinSonsLen(a, 3, c.c.config)
-    var L = len(a)
     when defined(nimsuggest):
       inc c.c.inTypeContext
-    a.sons[L-2] = semTemplBody(c, a.sons[L-2])
+    a[^2] = semTemplBody(c, a[^2])
     when defined(nimsuggest):
       dec c.c.inTypeContext
-    a.sons[L-1] = semTemplBody(c, a.sons[L-1])
-    for j in 0 .. L-3:
-      addLocalDecl(c, a.sons[j], symKind)
+    a[^1] = semTemplBody(c, a[^1])
+    for j in 0..<a.len-2:
+      addLocalDecl(c, a[j], symKind)
 
 proc semPattern(c: PContext, n: PNode): PNode
 
 proc semTemplBodySons(c: var TemplCtx, n: PNode): PNode =
   result = n
-  for i in 0 ..< n.len:
-    result.sons[i] = semTemplBody(c, n.sons[i])
+  for i in 0..<n.len:
+    result[i] = semTemplBody(c, n[i])
 
 proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
   result = n
@@ -362,7 +361,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
       else:
         result = semTemplSymbol(c.c, n, s, c.noGenSym > 0)
   of nkBind:
-    result = semTemplBody(c, n.sons[0])
+    result = semTemplBody(c, n[0])
   of nkBindStmt:
     result = semBindStmt(c.c, n, c.toBind)
   of nkMixinStmt:
@@ -371,109 +370,106 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
   of nkEmpty, nkSym..nkNilLit, nkComesFrom:
     discard
   of nkIfStmt:
-    for i in 0 ..< len(n):
-      var it = n.sons[i]
+    for i in 0..<n.len:
+      var it = n[i]
       if it.len == 2:
         openScope(c)
-        it.sons[0] = semTemplBody(c, it.sons[0])
-        it.sons[1] = semTemplBody(c, it.sons[1])
+        it[0] = semTemplBody(c, it[0])
+        it[1] = semTemplBody(c, it[1])
         closeScope(c)
       else:
-        n.sons[i] = semTemplBodyScope(c, it)
+        n[i] = semTemplBodyScope(c, it)
   of nkWhileStmt:
     openScope(c)
-    for i in 0 ..< len(n):
-      n.sons[i] = semTemplBody(c, n.sons[i])
+    for i in 0..<n.len:
+      n[i] = semTemplBody(c, n[i])
     closeScope(c)
   of nkCaseStmt:
     openScope(c)
-    n.sons[0] = semTemplBody(c, n.sons[0])
-    for i in 1 ..< len(n):
-      var a = n.sons[i]
+    n[0] = semTemplBody(c, n[0])
+    for i in 1..<n.len:
+      var a = n[i]
       checkMinSonsLen(a, 1, c.c.config)
-      var L = len(a)
-      for j in 0 .. L-2:
-        a.sons[j] = semTemplBody(c, a.sons[j])
-      a.sons[L-1] = semTemplBodyScope(c, a.sons[L-1])
+      for j in 0..<a.len-1:
+        a[j] = semTemplBody(c, a[j])
+      a[^1] = semTemplBodyScope(c, a[^1])
     closeScope(c)
   of nkForStmt, nkParForStmt:
-    var L = len(n)
     openScope(c)
-    n.sons[L-2] = semTemplBody(c, n.sons[L-2])
-    for i in 0 .. L - 3:
+    n[^2] = semTemplBody(c, n[^2])
+    for i in 0..<n.len - 2:
       if n[i].kind == nkVarTuple:
-        for j in 0 ..< len(n[i])-1:
+        for j in 0..<n[i].len-1:
           addLocalDecl(c, n[i][j], skForVar)
       else:
-        addLocalDecl(c, n.sons[i], skForVar)
+        addLocalDecl(c, n[i], skForVar)
     openScope(c)
-    n.sons[L-1] = semTemplBody(c, n.sons[L-1])
+    n[^1] = semTemplBody(c, n[^1])
     closeScope(c)
     closeScope(c)
   of nkBlockStmt, nkBlockExpr, nkBlockType:
     checkSonsLen(n, 2, c.c.config)
     openScope(c)
-    if n.sons[0].kind != nkEmpty:
-      addLocalDecl(c, n.sons[0], skLabel)
+    if n[0].kind != nkEmpty:
+      addLocalDecl(c, n[0], skLabel)
       when false:
         # labels are always 'gensym'ed:
-        let s = newGenSym(skLabel, n.sons[0], c)
+        let s = newGenSym(skLabel, n[0], c)
         addPrelimDecl(c.c, s)
         styleCheckDef(c.c.config, s)
         onDef(n[0].info, s)
-        n.sons[0] = newSymNode(s, n.sons[0].info)
-    n.sons[1] = semTemplBody(c, n.sons[1])
+        n[0] = newSymNode(s, n[0].info)
+    n[1] = semTemplBody(c, n[1])
     closeScope(c)
   of nkTryStmt, nkHiddenTryStmt:
     checkMinSonsLen(n, 2, c.c.config)
-    n.sons[0] = semTemplBodyScope(c, n.sons[0])
-    for i in 1 ..< len(n):
-      var a = n.sons[i]
+    n[0] = semTemplBodyScope(c, n[0])
+    for i in 1..<n.len:
+      var a = n[i]
       checkMinSonsLen(a, 1, c.c.config)
-      var L = len(a)
       openScope(c)
-      for j in 0 .. L-2:
-        if a.sons[j].isInfixAs():
-          addLocalDecl(c, a.sons[j].sons[2], skLet)
-          a.sons[j].sons[1] = semTemplBody(c, a.sons[j][1])
+      for j in 0..<a.len-1:
+        if a[j].isInfixAs():
+          addLocalDecl(c, a[j][2], skLet)
+          a[j][1] = semTemplBody(c, a[j][1])
         else:
-          a.sons[j] = semTemplBody(c, a.sons[j])
-      a.sons[L-1] = semTemplBodyScope(c, a.sons[L-1])
+          a[j] = semTemplBody(c, a[j])
+      a[^1] = semTemplBodyScope(c, a[^1])
       closeScope(c)
   of nkVarSection: semTemplSomeDecl(c, n, skVar)
   of nkLetSection: semTemplSomeDecl(c, n, skLet)
   of nkFormalParams:
     checkMinSonsLen(n, 1, c.c.config)
-    n.sons[0] = semTemplBody(c, n.sons[0])
+    n[0] = semTemplBody(c, n[0])
     semTemplSomeDecl(c, n, skParam, 1)
   of nkConstSection:
-    for i in 0 ..< len(n):
-      var a = n.sons[i]
+    for i in 0..<n.len:
+      var a = n[i]
       if a.kind == nkCommentStmt: continue
       if (a.kind != nkConstDef): illFormedAst(a, c.c.config)
       checkSonsLen(a, 3, c.c.config)
-      addLocalDecl(c, a.sons[0], skConst)
-      a.sons[1] = semTemplBody(c, a.sons[1])
-      a.sons[2] = semTemplBody(c, a.sons[2])
+      addLocalDecl(c, a[0], skConst)
+      a[1] = semTemplBody(c, a[1])
+      a[2] = semTemplBody(c, a[2])
   of nkTypeSection:
-    for i in 0 ..< len(n):
-      var a = n.sons[i]
+    for i in 0..<n.len:
+      var a = n[i]
       if a.kind == nkCommentStmt: continue
       if (a.kind != nkTypeDef): illFormedAst(a, c.c.config)
       checkSonsLen(a, 3, c.c.config)
-      addLocalDecl(c, a.sons[0], skType)
-    for i in 0 ..< len(n):
-      var a = n.sons[i]
+      addLocalDecl(c, a[0], skType)
+    for i in 0..<n.len:
+      var a = n[i]
       if a.kind == nkCommentStmt: continue
       if (a.kind != nkTypeDef): illFormedAst(a, c.c.config)
       checkSonsLen(a, 3, c.c.config)
-      if a.sons[1].kind != nkEmpty:
+      if a[1].kind != nkEmpty:
         openScope(c)
-        a.sons[1] = semTemplBody(c, a.sons[1])
-        a.sons[2] = semTemplBody(c, a.sons[2])
+        a[1] = semTemplBody(c, a[1])
+        a[2] = semTemplBody(c, a[2])
         closeScope(c)
       else:
-        a.sons[2] = semTemplBody(c, a.sons[2])
+        a[2] = semTemplBody(c, a[2])
   of nkProcDef, nkLambdaKinds:
     result = semRoutineInTemplBody(c, n, skProc)
   of nkFuncDef:
@@ -489,44 +485,44 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
   of nkConverterDef:
     result = semRoutineInTemplBody(c, n, skConverter)
   of nkPragmaExpr:
-    result.sons[0] = semTemplBody(c, n.sons[0])
+    result[0] = semTemplBody(c, n[0])
   of nkPostfix:
-    result.sons[1] = semTemplBody(c, n.sons[1])
+    result[1] = semTemplBody(c, n[1])
   of nkPragma:
     for x in n:
       if x.kind == nkExprColonExpr:
-        x.sons[1] = semTemplBody(c, x.sons[1])
+        x[1] = semTemplBody(c, x[1])
   of nkBracketExpr:
     result = newNodeI(nkCall, n.info)
     result.add newIdentNode(getIdent(c.c.cache, "[]"), n.info)
-    for i in 0 ..< n.len: result.add(n[i])
-    let n0 = semTemplBody(c, n.sons[0])
+    for i in 0..<n.len: result.add(n[i])
+    let n0 = semTemplBody(c, n[0])
     withBracketExpr c, n0:
       result = semTemplBodySons(c, result)
   of nkCurlyExpr:
     result = newNodeI(nkCall, n.info)
     result.add newIdentNode(getIdent(c.c.cache, "{}"), n.info)
-    for i in 0 ..< n.len: result.add(n[i])
+    for i in 0..<n.len: result.add(n[i])
     result = semTemplBodySons(c, result)
   of nkAsgn, nkFastAsgn:
     checkSonsLen(n, 2, c.c.config)
-    let a = n.sons[0]
-    let b = n.sons[1]
+    let a = n[0]
+    let b = n[1]
 
     let k = a.kind
     case k
     of nkBracketExpr:
       result = newNodeI(nkCall, n.info)
       result.add newIdentNode(getIdent(c.c.cache, "[]="), n.info)
-      for i in 0 ..< a.len: result.add(a[i])
+      for i in 0..<a.len: result.add(a[i])
       result.add(b)
-      let a0 = semTemplBody(c, a.sons[0])
+      let a0 = semTemplBody(c, a[0])
       withBracketExpr c, a0:
         result = semTemplBodySons(c, result)
     of nkCurlyExpr:
       result = newNodeI(nkCall, n.info)
       result.add newIdentNode(getIdent(c.c.cache, "{}="), n.info)
-      for i in 0 ..< a.len: result.add(a[i])
+      for i in 0..<a.len: result.add(a[i])
       result.add(b)
       result = semTemplBodySons(c, result)
     else:
@@ -554,18 +550,18 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
         return symChoice(c.c, n, s, scOpen, c.noGenSym > 0)
     if n.kind == nkDotExpr:
       result = n
-      result.sons[0] = semTemplBody(c, n.sons[0])
+      result[0] = semTemplBody(c, n[0])
       if optNimV019 notin c.c.config.globalOptions: inc c.noGenSym
-      result.sons[1] = semTemplBody(c, n.sons[1])
+      result[1] = semTemplBody(c, n[1])
       if optNimV019 notin c.c.config.globalOptions: dec c.noGenSym
     else:
       result = semTemplBodySons(c, n)
   of nkExprColonExpr, nkExprEqExpr:
     if n.len == 2:
       if optNimV019 notin c.c.config.globalOptions: inc c.noGenSym
-      result.sons[0] = semTemplBody(c, n.sons[0])
+      result[0] = semTemplBody(c, n[0])
       if optNimV019 notin c.c.config.globalOptions: dec c.noGenSym
-      result.sons[1] = semTemplBody(c, n.sons[1])
+      result[1] = semTemplBody(c, n[1])
     else:
       result = semTemplBodySons(c, n)
   else:
@@ -583,7 +579,7 @@ proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
       elif contains(c.toBind, s.id):
         result = symChoice(c.c, n, s, scClosed)
   of nkBind:
-    result = semTemplBodyDirty(c, n.sons[0])
+    result = semTemplBodyDirty(c, n[0])
   of nkBindStmt:
     result = semBindStmt(c.c, n, c.toBind)
   of nkEmpty, nkSym..nkNilLit, nkComesFrom:
@@ -596,16 +592,16 @@ proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
       if s != nil and contains(c.toBind, s.id):
         return symChoice(c.c, n, s, scClosed)
     result = n
-    for i in 0 ..< len(n):
-      result.sons[i] = semTemplBodyDirty(c, n.sons[i])
+    for i in 0..<n.len:
+      result[i] = semTemplBodyDirty(c, n[i])
 
 proc semTemplateDef(c: PContext, n: PNode): PNode =
   var s: PSym
   if isTopLevel(c):
-    s = semIdentVis(c, skTemplate, n.sons[0], {sfExported})
+    s = semIdentVis(c, skTemplate, n[0], {sfExported})
     incl(s.flags, sfGlobal)
   else:
-    s = semIdentVis(c, skTemplate, n.sons[0], {})
+    s = semIdentVis(c, skTemplate, n[0], {})
 
   if s.owner != nil:
     const names = ["!=", ">=", ">", "incl", "excl", "in", "notin", "isnot"]
@@ -619,41 +615,41 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
   #s.scope = c.currentScope
   pushOwner(c, s)
   openScope(c)
-  n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
-  if n.sons[pragmasPos].kind != nkEmpty:
-    pragma(c, s, n.sons[pragmasPos], templatePragmas)
+  n[namePos] = newSymNode(s, n[namePos].info)
+  if n[pragmasPos].kind != nkEmpty:
+    pragma(c, s, n[pragmasPos], templatePragmas)
 
   var gp: PNode
-  if n.sons[genericParamsPos].kind != nkEmpty:
-    n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
-    gp = n.sons[genericParamsPos]
+  if n[genericParamsPos].kind != nkEmpty:
+    n[genericParamsPos] = semGenericParamList(c, n[genericParamsPos])
+    gp = n[genericParamsPos]
   else:
     gp = newNodeI(nkGenericParams, n.info)
   # process parameters:
   var allUntyped = true
-  if n.sons[paramsPos].kind != nkEmpty:
-    semParamList(c, n.sons[paramsPos], gp, s)
+  if n[paramsPos].kind != nkEmpty:
+    semParamList(c, n[paramsPos], gp, s)
     # a template's parameters are not gensym'ed even if that was originally the
     # case as we determine whether it's a template parameter in the template
     # body by the absence of the sfGenSym flag:
-    for i in 1 .. s.typ.n.len-1:
-      let param = s.typ.n.sons[i].sym
+    for i in 1..<s.typ.n.len:
+      let param = s.typ.n[i].sym
       param.flags.incl sfTemplateParam
       param.flags.excl sfGenSym
       if param.typ.kind != tyUntyped: allUntyped = false
-    if len(gp) > 0:
-      if n.sons[genericParamsPos].kind == nkEmpty:
+    if gp.len > 0:
+      if n[genericParamsPos].kind == nkEmpty:
         # we have a list of implicit type parameters:
-        n.sons[genericParamsPos] = gp
+        n[genericParamsPos] = gp
   else:
     s.typ = newTypeS(tyProc, c)
     # XXX why do we need tyTyped as a return type again?
     s.typ.n = newNodeI(nkFormalParams, n.info)
     rawAddSon(s.typ, newTypeS(tyTyped, c))
-    addSon(s.typ.n, newNodeIT(nkType, n.info, s.typ.sons[0]))
+    s.typ.n.add newNodeIT(nkType, n.info, s.typ[0])
   if allUntyped: incl(s.flags, sfAllUntyped)
-  if n.sons[patternPos].kind != nkEmpty:
-    n.sons[patternPos] = semPattern(c, n.sons[patternPos])
+  if n[patternPos].kind != nkEmpty:
+    n[patternPos] = semPattern(c, n[patternPos])
   var ctx: TemplCtx
   ctx.toBind = initIntSet()
   ctx.toMixin = initIntSet()
@@ -661,26 +657,26 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
   ctx.c = c
   ctx.owner = s
   if sfDirty in s.flags:
-    n.sons[bodyPos] = semTemplBodyDirty(ctx, n.sons[bodyPos])
+    n[bodyPos] = semTemplBodyDirty(ctx, n[bodyPos])
   else:
-    n.sons[bodyPos] = semTemplBody(ctx, n.sons[bodyPos])
+    n[bodyPos] = semTemplBody(ctx, n[bodyPos])
   # only parameters are resolved, no type checking is performed
-  semIdeForTemplateOrGeneric(c, n.sons[bodyPos], ctx.cursorInBody)
+  semIdeForTemplateOrGeneric(c, n[bodyPos], ctx.cursorInBody)
   closeScope(c)
   popOwner(c)
   s.ast = n
   result = n
   if sfCustomPragma in s.flags:
-    if n.sons[bodyPos].kind != nkEmpty:
-      localError(c.config, n.sons[bodyPos].info, errImplOfXNotAllowed % s.name.s)
-  elif n.sons[bodyPos].kind == nkEmpty:
+    if n[bodyPos].kind != nkEmpty:
+      localError(c.config, n[bodyPos].info, errImplOfXNotAllowed % s.name.s)
+  elif n[bodyPos].kind == nkEmpty:
     localError(c.config, n.info, "implementation of '$1' expected" % s.name.s)
   var proto = searchForProc(c, c.currentScope, s)
   if proto == nil:
     addInterfaceOverloadableSymAt(c, c.currentScope, s)
   else:
     symTabReplace(c.currentScope.symbols, proto, s)
-  if n.sons[patternPos].kind != nkEmpty:
+  if n[patternPos].kind != nkEmpty:
     c.patterns.add(s)
 
 proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
@@ -694,7 +690,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
     # to use the param with the proper type though:
     incl(s.flags, sfUsed)
     onUse(n.info, s)
-    let x = c.owner.typ.n.sons[s.position+1].sym
+    let x = c.owner.typ.n[s.position+1].sym
     assert x.name == s.name
     result = newSymNode(x, n.info)
 
@@ -721,7 +717,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
       result = n
 
   proc stupidStmtListExpr(n: PNode): bool =
-    for i in 0 .. n.len-2:
+    for i in 0..<n.len-1:
       if n[i].kind notin {nkEmpty, nkCommentStmt}: return false
     result = true
 
@@ -738,14 +734,14 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
     # '(pattern){|x}' does the same but the matches will be gathered in 'x'
     if n.len != 2:
       localError(c.c.config, n.info, "invalid expression")
-    elif n.sons[1].kind == nkIdent:
-      n.sons[0] = semPatternBody(c, n.sons[0])
-      n.sons[1] = expectParam(c, n.sons[1])
-    elif n.sons[1].kind == nkPrefix and n.sons[1].sons[0].kind == nkIdent:
-      let opr = n.sons[1].sons[0]
+    elif n[1].kind == nkIdent:
+      n[0] = semPatternBody(c, n[0])
+      n[1] = expectParam(c, n[1])
+    elif n[1].kind == nkPrefix and n[1][0].kind == nkIdent:
+      let opr = n[1][0]
       if opr.ident.s == "|":
-        n.sons[0] = semPatternBody(c, n.sons[0])
-        n.sons[1].sons[1] = expectParam(c, n.sons[1].sons[1])
+        n[0] = semPatternBody(c, n[0])
+        n[1][1] = expectParam(c, n[1][1])
       else:
         localError(c.c.config, n.info, "invalid expression")
     else:
@@ -754,10 +750,10 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
     if stupidStmtListExpr(n):
       result = semPatternBody(c, n.lastSon)
     else:
-      for i in 0 ..< len(n):
-        result.sons[i] = semPatternBody(c, n.sons[i])
+      for i in 0..<n.len:
+        result[i] = semPatternBody(c, n[i])
   of nkCallKinds:
-    let s = qualifiedLookUp(c.c, n.sons[0], {})
+    let s = qualifiedLookUp(c.c, n[0], {})
     if s != nil:
       if s.owner == c.owner and s.kind == skParam: discard
       elif contains(c.toBind, s.id): discard
@@ -769,26 +765,26 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
       # infix notation, so that '`*`(a, b)' can be used for verbatim matching:
       if id.s == "*" or id.s == "**":
         result = newNodeI(nkPattern, n.info, n.len)
-        result.sons[0] = newIdentNode(id, n.info)
-        result.sons[1] = semPatternBody(c, n.sons[1])
-        result.sons[2] = expectParam(c, n.sons[2])
+        result[0] = newIdentNode(id, n.info)
+        result[1] = semPatternBody(c, n[1])
+        result[2] = expectParam(c, n[2])
         return
       elif id.s == "|":
         result = newNodeI(nkPattern, n.info, n.len)
-        result.sons[0] = newIdentNode(id, n.info)
-        result.sons[1] = semPatternBody(c, n.sons[1])
-        result.sons[2] = semPatternBody(c, n.sons[2])
+        result[0] = newIdentNode(id, n.info)
+        result[1] = semPatternBody(c, n[1])
+        result[2] = semPatternBody(c, n[2])
         return
 
     if n.kind == nkPrefix and (let id = considerQuotedIdent(c.c, n[0]); id != nil):
       if id.s == "~":
         result = newNodeI(nkPattern, n.info, n.len)
-        result.sons[0] = newIdentNode(id, n.info)
-        result.sons[1] = semPatternBody(c, n.sons[1])
+        result[0] = newIdentNode(id, n.info)
+        result[1] = semPatternBody(c, n[1])
         return
 
-    for i in 0 ..< len(n):
-      result.sons[i] = semPatternBody(c, n.sons[i])
+    for i in 0..<n.len:
+      result[i] = semPatternBody(c, n[i])
   else:
     # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
     # so we use the generic code for nkDotExpr too
@@ -801,10 +797,10 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
         else:
           return newIdentNode(s.name, n.info)
     of nkPar:
-      if n.len == 1: return semPatternBody(c, n.sons[0])
+      if n.len == 1: return semPatternBody(c, n[0])
     else: discard
-    for i in 0 ..< len(n):
-      result.sons[i] = semPatternBody(c, n.sons[i])
+    for i in 0..<n.len:
+      result[i] = semPatternBody(c, n[i])
 
 proc semPattern(c: PContext, n: PNode): PNode =
   openScope(c)
@@ -817,7 +813,7 @@ proc semPattern(c: PContext, n: PNode): PNode =
   result = flattenStmts(semPatternBody(ctx, n))
   if result.kind in {nkStmtList, nkStmtListExpr}:
     if result.len == 1:
-      result = result.sons[0]
+      result = result[0]
     elif result.len == 0:
       localError(c.config, n.info, "a pattern cannot be empty")
   closeScope(c)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 81efb9517..054e04a7c 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -67,35 +67,35 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
   result = newOrPrevType(tyEnum, prev, c)
   result.n = newNodeI(nkEnumTy, n.info)
   checkMinSonsLen(n, 1, c.config)
-  if n.sons[0].kind != nkEmpty:
-    base = semTypeNode(c, n.sons[0].sons[0], nil)
+  if n[0].kind != nkEmpty:
+    base = semTypeNode(c, n[0][0], nil)
     if base.kind != tyEnum:
-      localError(c.config, n.sons[0].info, "inheritance only works with an enum")
+      localError(c.config, n[0].info, "inheritance only works with an enum")
     counter = toInt64(lastOrd(c.config, base)) + 1
   rawAddSon(result, base)
   let isPure = result.sym != nil and sfPure in result.sym.flags
   var symbols: TStrTable
   if isPure: initStrTable(symbols)
   var hasNull = false
-  for i in 1 ..< len(n):
-    if n.sons[i].kind == nkEmpty: continue
-    case n.sons[i].kind
+  for i in 1..<n.len:
+    if n[i].kind == nkEmpty: continue
+    case n[i].kind
     of nkEnumFieldDef:
-      if n.sons[i].sons[0].kind == nkPragmaExpr:
-        e = newSymS(skEnumField, n.sons[i].sons[0].sons[0], c)
-        pragma(c, e, n.sons[i].sons[0].sons[1], enumFieldPragmas)
+      if n[i][0].kind == nkPragmaExpr:
+        e = newSymS(skEnumField, n[i][0][0], c)
+        pragma(c, e, n[i][0][1], enumFieldPragmas)
       else:
-        e = newSymS(skEnumField, n.sons[i].sons[0], c)
-      var v = semConstExpr(c, n.sons[i].sons[1])
+        e = newSymS(skEnumField, n[i][0], c)
+      var v = semConstExpr(c, n[i][1])
       var strVal: PNode = nil
       case skipTypes(v.typ, abstractInst-{tyTypeDesc}).kind
       of tyTuple:
-        if len(v) == 2:
-          strVal = v.sons[1] # second tuple part is the string value
+        if v.len == 2:
+          strVal = v[1] # second tuple part is the string value
           if skipTypes(strVal.typ, abstractInst).kind in {tyString, tyCString}:
-            if not isOrdinalType(v.sons[0].typ, allowEnumWithHoles=true):
-              localError(c.config, v.sons[0].info, errOrdinalTypeExpected & "; given: " & typeToString(v.sons[0].typ, preferDesc))
-            x = toInt64(getOrdValue(v.sons[0])) # first tuple part is the ordinal
+            if not isOrdinalType(v[0].typ, allowEnumWithHoles=true):
+              localError(c.config, v[0].info, errOrdinalTypeExpected & "; given: " & typeToString(v[0].typ, preferDesc))
+            x = toInt64(getOrdValue(v[0])) # first tuple part is the ordinal
           else:
             localError(c.config, strVal.info, errStringLiteralExpected)
         else:
@@ -110,17 +110,17 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
       if i != 1:
         if x != counter: incl(result.flags, tfEnumHasHoles)
         if x < counter:
-          localError(c.config, n.sons[i].info, errInvalidOrderInEnumX % e.name.s)
+          localError(c.config, n[i].info, errInvalidOrderInEnumX % e.name.s)
           x = counter
       e.ast = strVal # might be nil
       counter = x
     of nkSym:
-      e = n.sons[i].sym
+      e = n[i].sym
     of nkIdent, nkAccQuoted:
-      e = newSymS(skEnumField, n.sons[i], c)
+      e = newSymS(skEnumField, n[i], c)
     of nkPragmaExpr:
-      e = newSymS(skEnumField, n.sons[i].sons[0], c)
-      pragma(c, e, n.sons[i].sons[1], enumFieldPragmas)
+      e = newSymS(skEnumField, n[i][0], c)
+      pragma(c, e, n[i][1], enumFieldPragmas)
     else:
       illFormedAst(n[i], c.config)
     e.typ = result
@@ -130,7 +130,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
       incl(e.flags, sfUsed)
       incl(e.flags, sfExported)
       if not isPure: strTableAdd(c.module.tab, e)
-    addSon(result.n, newSymNode(e))
+    result.n.add newSymNode(e)
     styleCheckDef(c.config, e)
     onDef(e.info, e)
     if sfGenSym notin e.flags:
@@ -143,8 +143,8 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
 
 proc semSet(c: PContext, n: PNode, prev: PType): PType =
   result = newOrPrevType(tySet, prev, c)
-  if len(n) == 2 and n.sons[1].kind != nkEmpty:
-    var base = semTypeNode(c, n.sons[1], nil)
+  if n.len == 2 and n[1].kind != nkEmpty:
+    var base = semTypeNode(c, n[1], nil)
     addSonSkipIntLit(result, base)
     if base.kind in {tyGenericInst, tyAlias, tySink}: base = lastSon(base)
     if base.kind != tyGenericParam:
@@ -157,8 +157,8 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType =
     addSonSkipIntLit(result, errorType(c))
 
 proc semContainerArg(c: PContext; n: PNode, kindStr: string; result: PType) =
-  if len(n) == 2:
-    var base = semTypeNode(c, n.sons[1], nil)
+  if n.len == 2:
+    var base = semTypeNode(c, n[1], nil)
     if base.kind == tyVoid:
       localError(c.config, n.info, errTIsNotAConcreteType % typeToString(base))
     addSonSkipIntLit(result, base)
@@ -173,22 +173,22 @@ proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
 
 proc semVarargs(c: PContext, n: PNode, prev: PType): PType =
   result = newOrPrevType(tyVarargs, prev, c)
-  if len(n) == 2 or len(n) == 3:
-    var base = semTypeNode(c, n.sons[1], nil)
+  if n.len == 2 or n.len == 3:
+    var base = semTypeNode(c, n[1], nil)
     addSonSkipIntLit(result, base)
-    if len(n) == 3:
-      result.n = newIdentNode(considerQuotedIdent(c, n.sons[2]), n.sons[2].info)
+    if n.len == 3:
+      result.n = newIdentNode(considerQuotedIdent(c, n[2]), n[2].info)
   else:
     localError(c.config, n.info, errXExpectsOneTypeParam % "varargs")
     addSonSkipIntLit(result, errorType(c))
 
 proc semVarType(c: PContext, n: PNode, prev: PType): PType =
-  if len(n) == 1:
+  if n.len == 1:
     result = newOrPrevType(tyVar, prev, c)
-    var base = semTypeNode(c, n.sons[0], nil).skipTypes({tyTypeDesc})
+    var base = semTypeNode(c, n[0], nil).skipTypes({tyTypeDesc})
     if base.kind == tyVar:
       localError(c.config, n.info, "type 'var var' is not allowed")
-      base = base.sons[0]
+      base = base[0]
     addSonSkipIntLit(result, base)
   else:
     result = newConstraint(c, tyVar)
@@ -196,7 +196,7 @@ proc semVarType(c: PContext, n: PNode, prev: PType): PType =
 proc semDistinct(c: PContext, n: PNode, prev: PType): PType =
   if n.len == 0: return newConstraint(c, tyDistinct)
   result = newOrPrevType(tyDistinct, prev, c)
-  addSonSkipIntLit(result, semTypeNode(c, n.sons[0], nil))
+  addSonSkipIntLit(result, semTypeNode(c, n[0], nil))
   if n.len > 1: result.n = n[1]
 
 proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
@@ -233,10 +233,10 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
 
   for i in 0..1:
     if hasUnresolvedArgs(c, range[i]):
-      result.n.addSon makeStaticExpr(c, range[i])
+      result.n.add makeStaticExpr(c, range[i])
       result.flags.incl tfUnresolved
     else:
-      result.n.addSon semConstExpr(c, range[i])
+      result.n.add semConstExpr(c, range[i])
 
   if (result.n[0].kind in {nkFloatLit..nkFloat64Lit} and classify(result.n[0].floatVal) == fcNan) or
       (result.n[1].kind in {nkFloatLit..nkFloat64Lit} and classify(result.n[1].floatVal) == fcNan):
@@ -249,25 +249,25 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
 
 proc semRange(c: PContext, n: PNode, prev: PType): PType =
   result = nil
-  if len(n) == 2:
+  if n.len == 2:
     if isRange(n[1]):
       result = semRangeAux(c, n[1], prev)
       let n = result.n
-      if n.sons[0].kind in {nkCharLit..nkUInt64Lit} and n.sons[0].intVal > 0:
+      if n[0].kind in {nkCharLit..nkUInt64Lit} and n[0].intVal > 0:
         incl(result.flags, tfNeedsInit)
-      elif n.sons[1].kind in {nkCharLit..nkUInt64Lit} and n.sons[1].intVal < 0:
+      elif n[1].kind in {nkCharLit..nkUInt64Lit} and n[1].intVal < 0:
         incl(result.flags, tfNeedsInit)
-      elif n.sons[0].kind in {nkFloatLit..nkFloat64Lit} and
-          n.sons[0].floatVal > 0.0:
+      elif n[0].kind in {nkFloatLit..nkFloat64Lit} and
+          n[0].floatVal > 0.0:
         incl(result.flags, tfNeedsInit)
-      elif n.sons[1].kind in {nkFloatLit..nkFloat64Lit} and
-          n.sons[1].floatVal < 0.0:
+      elif n[1].kind in {nkFloatLit..nkFloat64Lit} and
+          n[1].floatVal < 0.0:
         incl(result.flags, tfNeedsInit)
     else:
       if n[1].kind == nkInfix and considerQuotedIdent(c, n[1][0]).s == "..<":
         localError(c.config, n[0].info, "range types need to be constructed with '..', '..<' is not supported")
       else:
-        localError(c.config, n.sons[0].info, "expected range")
+        localError(c.config, n[0].info, "expected range")
       result = newOrPrevType(tyError, prev, c)
   else:
     localError(c.config, n.info, errXExpectsOneTypeParam % "range")
@@ -315,7 +315,7 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
 
 proc semArray(c: PContext, n: PNode, prev: PType): PType =
   var base: PType
-  if len(n) == 3:
+  if n.len == 3:
     # 3 = length(array indx base)
     let indx = semArrayIndex(c, n[1])
     var indxB = indx
@@ -324,11 +324,11 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
       if indxB.skipTypes({tyRange}).kind in {tyUInt, tyUInt64}:
         discard
       elif not isOrdinalType(indxB):
-        localError(c.config, n.sons[1].info, errOrdinalTypeExpected)
+        localError(c.config, n[1].info, errOrdinalTypeExpected)
       elif enumHasHoles(indxB):
-        localError(c.config, n.sons[1].info, "enum '$1' has holes" %
+        localError(c.config, n[1].info, "enum '$1' has holes" %
                    typeToString(indxB.skipTypes({tyRange})))
-    base = semTypeNode(c, n.sons[2], nil)
+    base = semTypeNode(c, n[2], nil)
     # ensure we only construct a tyArray when there was no error (bug #3048):
     result = newOrPrevType(tyArray, prev, c)
     # bug #6682: Do not propagate initialization requirements etc for the
@@ -341,11 +341,11 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
 
 proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
   result = newOrPrevType(tyOrdinal, prev, c)
-  if len(n) == 2:
-    var base = semTypeNode(c, n.sons[1], nil)
+  if n.len == 2:
+    var base = semTypeNode(c, n[1], nil)
     if base.kind != tyGenericParam:
       if not isOrdinalType(base):
-        localError(c.config, n.sons[1].info, errOrdinalTypeExpected)
+        localError(c.config, n[1].info, errOrdinalTypeExpected)
     addSonSkipIntLit(result, base)
   else:
     localError(c.config, n.info, errXExpectsOneTypeParam % "ordinal")
@@ -367,7 +367,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
         # it's not bound when it's used multiple times in the
         # proc signature for example
         if c.inGenericInst > 0:
-          let bound = result.typ.sons[0].sym
+          let bound = result.typ[0].sym
           if bound != nil: return bound
           return result
         if result.typ.sym == nil:
@@ -414,7 +414,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
       result = errorSym(c, n)
 
 proc semAnonTuple(c: PContext, n: PNode, prev: PType): PType =
-  if len(n) == 0:
+  if n.len == 0:
     localError(c.config, n.info, errTypeExpected)
   result = newOrPrevType(tyTuple, prev, c)
   for it in n:
@@ -426,29 +426,28 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
   result.n = newNodeI(nkRecList, n.info)
   var check = initIntSet()
   var counter = 0
-  for i in ord(n.kind == nkBracketExpr) ..< len(n):
-    var a = n.sons[i]
+  for i in ord(n.kind == nkBracketExpr)..<n.len:
+    var a = n[i]
     if (a.kind != nkIdentDefs): illFormedAst(a, c.config)
     checkMinSonsLen(a, 3, c.config)
-    var length = len(a)
-    if a.sons[length - 2].kind != nkEmpty:
-      typ = semTypeNode(c, a.sons[length - 2], nil)
+    if a[^2].kind != nkEmpty:
+      typ = semTypeNode(c, a[^2], nil)
     else:
       localError(c.config, a.info, errTypeExpected)
       typ = errorType(c)
-    if a.sons[length - 1].kind != nkEmpty:
-      localError(c.config, a.sons[length - 1].info, errInitHereNotAllowed)
-    for j in 0 .. length - 3:
-      var field = newSymG(skField, a.sons[j], c)
+    if a[^1].kind != nkEmpty:
+      localError(c.config, a[^1].info, errInitHereNotAllowed)
+    for j in 0..<a.len - 2:
+      var field = newSymG(skField, a[j], c)
       field.typ = typ
       field.position = counter
       inc(counter)
       if containsOrIncl(check, field.name.id):
-        localError(c.config, a.sons[j].info, "attempt to redefine: '" & field.name.s & "'")
+        localError(c.config, a[j].info, "attempt to redefine: '" & field.name.s & "'")
       else:
-        addSon(result.n, newSymNode(field))
+        result.n.add newSymNode(field)
         addSonSkipIntLit(result, typ)
-      styleCheckDef(c.config, a.sons[j].info, field)
+      styleCheckDef(c.config, a[j].info, field)
       onDef(field.info, field)
   if result.n.len == 0: result.n = nil
   if isTupleRecursive(result):
@@ -460,18 +459,18 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
                  allowed: TSymFlags): PSym =
   # identifier with visibility
   if n.kind == nkPostfix:
-    if len(n) == 2:
+    if n.len == 2:
       # for gensym'ed identifiers the identifier may already have been
       # transformed to a symbol and we need to use that here:
-      result = newSymG(kind, n.sons[1], c)
-      var v = considerQuotedIdent(c, n.sons[0])
+      result = newSymG(kind, n[1], c)
+      var v = considerQuotedIdent(c, n[0])
       if sfExported in allowed and v.id == ord(wStar):
         incl(result.flags, sfExported)
       else:
         if not (sfExported in allowed):
-          localError(c.config, n.sons[0].info, errXOnlyAtModuleScope % "export")
+          localError(c.config, n[0].info, errXOnlyAtModuleScope % "export")
         else:
-          localError(c.config, n.sons[0].info, errInvalidVisibilityX % renderTree(n[0]))
+          localError(c.config, n[0].info, errInvalidVisibilityX % renderTree(n[0]))
     else:
       illFormedAst(n, c.config)
   else:
@@ -481,33 +480,33 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
                         allowed: TSymFlags): PSym =
   if n.kind == nkPragmaExpr:
     checkSonsLen(n, 2, c.config)
-    result = semIdentVis(c, kind, n.sons[0], allowed)
+    result = semIdentVis(c, kind, n[0], allowed)
     case kind
     of skType:
       # process pragmas later, because result.typ has not been set yet
       discard
-    of skField: pragma(c, result, n.sons[1], fieldPragmas)
-    of skVar:   pragma(c, result, n.sons[1], varPragmas)
-    of skLet:   pragma(c, result, n.sons[1], letPragmas)
-    of skConst: pragma(c, result, n.sons[1], constPragmas)
+    of skField: pragma(c, result, n[1], fieldPragmas)
+    of skVar:   pragma(c, result, n[1], varPragmas)
+    of skLet:   pragma(c, result, n[1], letPragmas)
+    of skConst: pragma(c, result, n[1], constPragmas)
     else: discard
   else:
     result = semIdentVis(c, kind, n, allowed)
 
 proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
   let ex = t[branchIndex][currentEx].skipConv
-  for i in 1 .. branchIndex:
-    for j in 0 .. len(t.sons[i]) - 2:
+  for i in 1..branchIndex:
+    for j in 0..<t[i].len - 1:
       if i == branchIndex and j == currentEx: break
-      if overlap(t.sons[i].sons[j].skipConv, ex):
+      if overlap(t[i][j].skipConv, ex):
         localError(c.config, ex.info, errDuplicateCaseLabel)
 
 proc semBranchRange(c: PContext, t, a, b: PNode, covered: var Int128): PNode =
   checkMinSonsLen(t, 1, c.config)
   let ac = semConstExpr(c, a)
   let bc = semConstExpr(c, b)
-  let at = fitNode(c, t.sons[0].typ, ac, ac.info).skipConvTakeType
-  let bt = fitNode(c, t.sons[0].typ, bc, bc.info).skipConvTakeType
+  let at = fitNode(c, t[0].typ, ac, ac.info).skipConvTakeType
+  let bt = fitNode(c, t[0].typ, bc, bc.info).skipConvTakeType
 
   result = newNodeI(nkRange, a.info)
   result.add(at)
@@ -518,65 +517,65 @@ proc semBranchRange(c: PContext, t, a, b: PNode, covered: var Int128): PNode =
 proc semCaseBranchRange(c: PContext, t, b: PNode,
                         covered: var Int128): PNode =
   checkSonsLen(b, 3, c.config)
-  result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
+  result = semBranchRange(c, t, b[1], b[2], covered)
 
 proc semCaseBranchSetElem(c: PContext, t, b: PNode,
                           covered: var Int128): PNode =
   if isRange(b):
     checkSonsLen(b, 3, c.config)
-    result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
+    result = semBranchRange(c, t, b[1], b[2], covered)
   elif b.kind == nkRange:
     checkSonsLen(b, 2, c.config)
-    result = semBranchRange(c, t, b.sons[0], b.sons[1], covered)
+    result = semBranchRange(c, t, b[0], b[1], covered)
   else:
-    result = fitNode(c, t.sons[0].typ, b, b.info)
+    result = fitNode(c, t[0].typ, b, b.info)
     inc(covered)
 
 proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
                    covered: var Int128) =
-  let lastIndex = len(branch) - 2
+  let lastIndex = branch.len - 2
   for i in 0..lastIndex:
-    var b = branch.sons[i]
+    var b = branch[i]
     if b.kind == nkRange:
-      branch.sons[i] = b
+      branch[i] = b
     elif isRange(b):
-      branch.sons[i] = semCaseBranchRange(c, t, b, covered)
+      branch[i] = semCaseBranchRange(c, t, b, covered)
     else:
       # constant sets and arrays are allowed:
       var r = semConstExpr(c, b)
-      if r.kind in {nkCurly, nkBracket} and len(r) == 0  and len(branch)==2:
+      if r.kind in {nkCurly, nkBracket} and r.len == 0 and branch.len == 2:
         # discarding ``{}`` and ``[]`` branches silently
         delSon(branch, 0)
         return
-      elif r.kind notin {nkCurly, nkBracket} or len(r) == 0:
+      elif r.kind notin {nkCurly, nkBracket} or r.len == 0:
         checkMinSonsLen(t, 1, c.config)
-        var tmp = fitNode(c, t.sons[0].typ, r, r.info)
+        var tmp = fitNode(c, t[0].typ, r, r.info)
         # the call to fitNode may introduce a call to a converter
         if tmp.kind in {nkHiddenCallConv}: tmp = semConstExpr(c, tmp)
-        branch.sons[i] = skipConv(tmp)
+        branch[i] = skipConv(tmp)
         inc(covered)
       else:
         if r.kind == nkCurly:
           r = deduplicate(c.config, r)
 
-        # first element is special and will overwrite: branch.sons[i]:
-        branch.sons[i] = semCaseBranchSetElem(c, t, r[0], covered)
+        # first element is special and will overwrite: branch[i]:
+        branch[i] = semCaseBranchSetElem(c, t, r[0], covered)
 
         # other elements have to be added to ``branch``
-        for j in 1 ..< r.len:
+        for j in 1..<r.len:
           branch.add(semCaseBranchSetElem(c, t, r[j], covered))
           # caution! last son of branch must be the actions to execute:
-          swap(branch.sons[^2], branch.sons[^1])
+          swap(branch[^2], branch[^1])
     checkForOverlap(c, t, i, branchIndex)
 
   # Elements added above needs to be checked for overlaps.
-  for i in lastIndex.succ..(len(branch) - 2):
+  for i in lastIndex.succ..<branch.len - 1:
     checkForOverlap(c, t, i, branchIndex)
 
 proc toCover(c: PContext, t: PType): Int128 =
   let t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
   if t2.kind == tyEnum and enumHasHoles(t2):
-    result = toInt128(len(t2.n))
+    result = toInt128(t2.n.len)
   else:
     # <----
     let t = skipTypes(t, abstractVar-{tyTypeDesc})
@@ -595,14 +594,14 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
 
 proc formatMissingEnums(n: PNode): string =
   var coveredCases = initIntSet()
-  for i in 1 ..< n.len:
+  for i in 1..<n.len:
     let ofBranch = n[i]
-    for j in 0 ..< ofBranch.len - 1:
+    for j in 0..<ofBranch.len - 1:
       let child = ofBranch[j]
       if child.kind == nkIntLit:
         coveredCases.incl(child.intVal.int)
       elif child.kind == nkRange:
-        for k in child[0].intVal.int .. child[1].intVal.int:
+        for k in child[0].intVal.int..child[1].intVal.int:
           coveredCases.incl k
   for child in n[0].typ.n.sons:
     if child.sym.position notin coveredCases:
@@ -614,14 +613,14 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
                    father: PNode, rectype: PType) =
   var a = copyNode(n)
   checkMinSonsLen(n, 2, c.config)
-  semRecordNodeAux(c, n.sons[0], check, pos, a, rectype, hasCaseFields = true)
-  if a.sons[0].kind != nkSym:
+  semRecordNodeAux(c, n[0], check, pos, a, rectype, hasCaseFields = true)
+  if a[0].kind != nkSym:
     internalError(c.config, "semRecordCase: discriminant is no symbol")
     return
-  incl(a.sons[0].sym.flags, sfDiscriminant)
+  incl(a[0].sym.flags, sfDiscriminant)
   var covered: Int128 = toInt128(0)
   var chckCovered = false
-  var typ = skipTypes(a.sons[0].typ, abstractVar-{tyTypeDesc})
+  var typ = skipTypes(a[0].typ, abstractVar-{tyTypeDesc})
   const shouldChckCovered = {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool}
   case typ.kind
   of shouldChckCovered:
@@ -629,40 +628,40 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
   of tyFloat..tyFloat128, tyString, tyError:
     discard
   of tyRange:
-    if skipTypes(typ.sons[0], abstractInst).kind in shouldChckCovered:
+    if skipTypes(typ[0], abstractInst).kind in shouldChckCovered:
       chckCovered = true
   of tyForward:
-    errorUndeclaredIdentifier(c, n.sons[0].info, typ.sym.name.s)
+    errorUndeclaredIdentifier(c, n[0].info, typ.sym.name.s)
   elif not isOrdinalType(typ):
-    localError(c.config, n.sons[0].info, "selector must be of an ordinal type, float or string")
+    localError(c.config, n[0].info, "selector must be of an ordinal type, float or string")
   if firstOrd(c.config, typ) != 0:
-    localError(c.config, n.info, "low(" & $a.sons[0].sym.name.s &
+    localError(c.config, n.info, "low(" & $a[0].sym.name.s &
                                      ") must be 0 for discriminant")
   elif lengthOrd(c.config, typ) > 0x00007FFF:
-    localError(c.config, n.info, "len($1) must be less than 32768" % a.sons[0].sym.name.s)
+    localError(c.config, n.info, "len($1) must be less than 32768" % a[0].sym.name.s)
 
-  for i in 1 ..< len(n):
-    var b = copyTree(n.sons[i])
-    addSon(a, b)
-    case n.sons[i].kind
+  for i in 1..<n.len:
+    var b = copyTree(n[i])
+    a.add b
+    case n[i].kind
     of nkOfBranch:
       checkMinSonsLen(b, 2, c.config)
       semCaseBranch(c, a, b, i, covered)
     of nkElse:
       checkSonsLen(b, 1, c.config)
-      if chckCovered and covered == toCover(c, a.sons[0].typ):
+      if chckCovered and covered == toCover(c, a[0].typ):
         localError(c.config, b.info, "invalid else, all cases are already covered")
       chckCovered = false
     else: illFormedAst(n, c.config)
-    delSon(b, len(b) - 1)
-    semRecordNodeAux(c, lastSon(n.sons[i]), check, pos, b, rectype, hasCaseFields = true)
-  if chckCovered and covered != toCover(c, a.sons[0].typ):
-    if a.sons[0].typ.kind == tyEnum:
+    delSon(b, b.len - 1)
+    semRecordNodeAux(c, lastSon(n[i]), check, pos, b, rectype, hasCaseFields = true)
+  if chckCovered and covered != toCover(c, a[0].typ):
+    if a[0].typ.kind == tyEnum:
       localError(c.config, a.info, "not all cases are covered; missing: {$1}" %
         formatMissingEnums(a))
     else:
       localError(c.config, a.info, "not all cases are covered")
-  addSon(father, a)
+  father.add a
 
 proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
                       father: PNode, rectype: PType, hasCaseFields = false) =
@@ -670,22 +669,22 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
   case n.kind
   of nkRecWhen:
     var branch: PNode = nil   # the branch to take
-    for i in 0 ..< len(n):
-      var it = n.sons[i]
+    for i in 0..<n.len:
+      var it = n[i]
       if it == nil: illFormedAst(n, c.config)
       var idx = 1
       case it.kind
       of nkElifBranch:
         checkSonsLen(it, 2, c.config)
         if c.inGenericContext == 0:
-          var e = semConstBoolExpr(c, it.sons[0])
+          var e = semConstBoolExpr(c, it[0])
           if e.kind != nkIntLit: internalError(c.config, e.info, "semRecordNodeAux")
-          elif e.intVal != 0 and branch == nil: branch = it.sons[1]
+          elif e.intVal != 0 and branch == nil: branch = it[1]
         else:
-          it.sons[0] = forceBool(c, semExprWithType(c, it.sons[0]))
+          it[0] = forceBool(c, semExprWithType(c, it[0]))
       of nkElse:
         checkSonsLen(it, 1, c.config)
-        if branch == nil: branch = it.sons[0]
+        if branch == nil: branch = it[0]
         idx = 0
       else: illFormedAst(n, c.config)
       if c.inGenericContext > 0:
@@ -694,45 +693,44 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
         assign(newCheck, check)
         var newPos = pos
         var newf = newNodeI(nkRecList, n.info)
-        semRecordNodeAux(c, it.sons[idx], newCheck, newPos, newf, rectype)
-        it.sons[idx] = if newf.len == 1: newf[0] else: newf
+        semRecordNodeAux(c, it[idx], newCheck, newPos, newf, rectype)
+        it[idx] = if newf.len == 1: newf[0] else: newf
     if c.inGenericContext > 0:
-      addSon(father, n)
+      father.add n
     elif branch != nil:
       semRecordNodeAux(c, branch, check, pos, father, rectype)
   of nkRecCase:
     semRecordCase(c, n, check, pos, father, rectype)
   of nkNilLit:
-    if father.kind != nkRecList: addSon(father, newNodeI(nkRecList, n.info))
+    if father.kind != nkRecList: father.add newNodeI(nkRecList, n.info)
   of nkRecList:
     # attempt to keep the nesting at a sane level:
     var a = if father.kind == nkRecList: father else: copyNode(n)
-    for i in 0 ..< len(n):
-      semRecordNodeAux(c, n.sons[i], check, pos, a, rectype)
-    if a != father: addSon(father, a)
+    for i in 0..<n.len:
+      semRecordNodeAux(c, n[i], check, pos, a, rectype)
+    if a != father: father.add a
   of nkIdentDefs:
     checkMinSonsLen(n, 3, c.config)
-    var length = len(n)
     var a: PNode
-    if father.kind != nkRecList and length>=4: a = newNodeI(nkRecList, n.info)
+    if father.kind != nkRecList and n.len >= 4: a = newNodeI(nkRecList, n.info)
     else: a = newNodeI(nkEmpty, n.info)
-    if n.sons[length-1].kind != nkEmpty:
-      localError(c.config, n.sons[length-1].info, errInitHereNotAllowed)
+    if n[^1].kind != nkEmpty:
+      localError(c.config, n[^1].info, errInitHereNotAllowed)
     var typ: PType
-    if n.sons[length-2].kind == nkEmpty:
+    if n[^2].kind == nkEmpty:
       localError(c.config, n.info, errTypeExpected)
       typ = errorType(c)
     else:
-      typ = semTypeNode(c, n.sons[length-2], nil)
+      typ = semTypeNode(c, n[^2], nil)
       propagateToOwner(rectype, typ)
     var fieldOwner = if c.inGenericContext > 0: c.getCurrOwner
                      else: rectype.sym
-    for i in 0 .. len(n)-3:
-      var f = semIdentWithPragma(c, skField, n.sons[i], {sfExported})
-      let info = if n.sons[i].kind == nkPostfix:
-                   n.sons[i].sons[1].info
+    for i in 0..<n.len-2:
+      var f = semIdentWithPragma(c, skField, n[i], {sfExported})
+      let info = if n[i].kind == nkPostfix:
+                   n[i][1].info
                  else:
-                   n.sons[i].info
+                   n[i].info
       suggestSym(c.config, info, f, c.graph.usageSym)
       f.typ = typ
       f.position = pos
@@ -745,18 +743,18 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
       inc(pos)
       if containsOrIncl(check, f.name.id):
         localError(c.config, info, "attempt to redefine: '" & f.name.s & "'")
-      if a.kind == nkEmpty: addSon(father, newSymNode(f))
-      else: addSon(a, newSymNode(f))
+      if a.kind == nkEmpty: father.add newSymNode(f)
+      else: a.add newSymNode(f)
       styleCheckDef(c.config, f)
       onDef(f.info, f)
-    if a.kind != nkEmpty: addSon(father, a)
+    if a.kind != nkEmpty: father.add a
   of nkSym:
     # This branch only valid during generic object
     # inherited from generic/partial specialized parent second check.
     # There is no branch validity check here
     if containsOrIncl(check, n.sym.name.id):
       localError(c.config, n.info, "attempt to redefine: '" & n.sym.name.s & "'")
-    addSon(father, n)
+    father.add n
   of nkEmpty: discard
   else: illFormedAst(n, c.config)
 
@@ -764,16 +762,16 @@ proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
                            n: PNode) =
   case n.kind
   of nkRecCase:
-    if (n.sons[0].kind != nkSym): internalError(c.config, n.info, "addInheritedFieldsAux")
-    addInheritedFieldsAux(c, check, pos, n.sons[0])
-    for i in 1 ..< len(n):
-      case n.sons[i].kind
+    if (n[0].kind != nkSym): internalError(c.config, n.info, "addInheritedFieldsAux")
+    addInheritedFieldsAux(c, check, pos, n[0])
+    for i in 1..<n.len:
+      case n[i].kind
       of nkOfBranch, nkElse:
-        addInheritedFieldsAux(c, check, pos, lastSon(n.sons[i]))
+        addInheritedFieldsAux(c, check, pos, lastSon(n[i]))
       else: internalError(c.config, n.info, "addInheritedFieldsAux(record case branch)")
   of nkRecList, nkRecWhen, nkElifBranch, nkElse:
-    for i in 0 ..< len(n):
-      addInheritedFieldsAux(c, check, pos, n.sons[i])
+    for i in 0..<n.len:
+      addInheritedFieldsAux(c, check, pos, n[i])
   of nkSym:
     incl(check, n.sym.name.id)
     inc(pos)
@@ -782,15 +780,15 @@ proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
 proc skipGenericInvocation(t: PType): PType {.inline.} =
   result = t
   if result.kind == tyGenericInvocation:
-    result = result.sons[0]
+    result = result[0]
   while result.kind in {tyGenericInst, tyGenericBody, tyRef, tyPtr, tyAlias, tySink, tyOwned}:
     result = lastSon(result)
 
 proc addInheritedFields(c: PContext, check: var IntSet, pos: var int,
                         obj: PType) =
   assert obj.kind == tyObject
-  if (len(obj) > 0) and (obj.sons[0] != nil):
-    addInheritedFields(c, check, pos, obj.sons[0].skipGenericInvocation)
+  if (obj.len > 0) and (obj[0] != nil):
+    addInheritedFields(c, check, pos, obj[0].skipGenericInvocation)
   addInheritedFieldsAux(c, check, pos, obj.n)
 
 proc semObjectNode(c: PContext, n: PNode, prev: PType; isInheritable: bool): PType =
@@ -799,10 +797,10 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; isInheritable: bool): PTy
   var check = initIntSet()
   var pos = 0
   var base, realBase: PType = nil
-  # n.sons[0] contains the pragmas (if any). We process these later...
+  # n[0] contains the pragmas (if any). We process these later...
   checkSonsLen(n, 3, c.config)
-  if n.sons[1].kind != nkEmpty:
-    realBase = semTypeNode(c, n.sons[1].sons[0], nil)
+  if n[1].kind != nkEmpty:
+    realBase = semTypeNode(c, n[1][0], nil)
     base = skipTypesOrNil(realBase, skipPtrs)
     if base.isNil:
       localError(c.config, n.info, "cannot inherit from a type that is not an object type")
@@ -818,7 +816,7 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; isInheritable: bool): PTy
           addInheritedFields(c, check, pos, concreteBase)
       else:
         if concreteBase.kind != tyError:
-          localError(c.config, n.sons[1].info, "inheritance only works with non-final objects; " &
+          localError(c.config, n[1].info, "inheritance only works with non-final objects; " &
              "to enable inheritance write '" & typeToString(realBase) & " of RootObj'")
         base = nil
         realBase = nil
@@ -832,12 +830,12 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; isInheritable: bool): PTy
   else:
     # partial object so add things to the check
     addInheritedFields(c, check, pos, result)
-  semRecordNodeAux(c, n.sons[2], check, pos, result.n, result)
-  if n.sons[0].kind != nkEmpty:
+  semRecordNodeAux(c, n[2], check, pos, result.n, result)
+  if n[0].kind != nkEmpty:
     # dummy symbol for `pragma`:
     var s = newSymS(skType, newIdentNode(getIdent(c.cache, "dummy"), n.info), c)
     s.typ = result
-    pragma(c, s, n.sons[0], typePragmas)
+    pragma(c, s, n[0], typePragmas)
   if base == nil and tfInheritable notin result.flags:
     incl(result.flags, tfFinal)
 
@@ -862,7 +860,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
     var isNilable = false
     var isOwned = false
     # check every except the last is an object:
-    for i in isCall .. n.len-2:
+    for i in isCall..<n.len-1:
       let ni = n[i]
       if ni.kind == nkNilLit:
         isNilable = true
@@ -938,9 +936,9 @@ proc addImplicitGeneric(c: PContext; typeClass: PType, typId: PIdent;
   let finalTypId = if typId != nil: typId
                     else: getIdent(c.cache, paramName & ":type")
   # is this a bindOnce type class already present in the param list?
-  for i in 0 ..< genericParams.len:
-    if genericParams.sons[i].sym.name.id == finalTypId.id:
-      return genericParams.sons[i].typ
+  for i in 0..<genericParams.len:
+    if genericParams[i].sym.name.id == finalTypId.id:
+      return genericParams[i].typ
 
   let owner = if typeClass.sym != nil: typeClass.sym
               else: getCurrOwner(c)
@@ -950,7 +948,7 @@ proc addImplicitGeneric(c: PContext; typeClass: PType, typId: PIdent;
   s.linkTo(typeClass)
   typeClass.flags.incl tfImplicitTypeParam
   s.position = genericParams.len
-  genericParams.addSon(newSymNode(s))
+  genericParams.add newSymNode(s)
   result = typeClass
   addDecl(c, s)
 
@@ -1016,21 +1014,21 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
                                   @[newTypeS(paramType.kind, c)])
       result = addImplicitGeneric(c, typ, paramTypId, info, genericParams, paramName)
     else:
-      for i in 0 ..< paramType.len:
-        if paramType.sons[i] == paramType:
+      for i in 0..<paramType.len:
+        if paramType[i] == paramType:
           globalError(c.config, info, errIllegalRecursionInTypeX % typeToString(paramType))
-        var lifted = recurse(paramType.sons[i])
+        var lifted = recurse(paramType[i])
         if lifted != nil:
-          paramType.sons[i] = lifted
+          paramType[i] = lifted
           result = paramType
 
   of tyGenericBody:
     result = newTypeS(tyGenericInvocation, c)
     result.rawAddSon(paramType)
 
-    for i in 0 .. paramType.len - 2:
-      if paramType.sons[i].kind == tyStatic:
-        var staticCopy = paramType.sons[i].exactReplica
+    for i in 0..<paramType.len - 1:
+      if paramType[i].kind == tyStatic:
+        var staticCopy = paramType[i].exactReplica
         staticCopy.flags.incl tfInferrableStatic
         result.rawAddSon staticCopy
       else:
@@ -1045,7 +1043,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
                                   allowMetaTypes = true)
     result = newTypeWithSons(c, tyCompositeTypeClass, @[paramType, x])
     #result = newTypeS(tyCompositeTypeClass, c)
-    #for i in 0..<x.len: result.rawAddSon(x.sons[i])
+    #for i in 0..<x.len: result.rawAddSon(x[i])
     result = addImplicitGeneric(c, result, paramTypId, info, genericParams, paramName)
 
   of tyGenericInst:
@@ -1054,10 +1052,10 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
       cp.kind = tyUserTypeClassInst
       return addImplicitGeneric(c, cp, paramTypId, info, genericParams, paramName)
 
-    for i in 1 .. paramType.len-2:
-      var lifted = recurse(paramType.sons[i])
+    for i in 1..<paramType.len-1:
+      var lifted = recurse(paramType[i])
       if lifted != nil:
-        paramType.sons[i] = lifted
+        paramType[i] = lifted
         result = paramType
         result.lastSon.shouldHaveMeta
 
@@ -1068,10 +1066,10 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
       #result.shouldHaveMeta
 
   of tyGenericInvocation:
-    for i in 1 ..< paramType.len:
+    for i in 1..<paramType.len:
       #if paramType[i].kind != tyTypeDesc:
-      let lifted = recurse(paramType.sons[i])
-      if lifted != nil: paramType.sons[i] = lifted
+      let lifted = recurse(paramType[i])
+      if lifted != nil: paramType[i] = lifted
 
     let body = paramType.base
     if body.kind in {tyForward, tyError}:
@@ -1101,7 +1099,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
 
 proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType =
   if n.kind == nkCurlyExpr:
-    result = semTypeNode(c, n.sons[0], nil)
+    result = semTypeNode(c, n[0], nil)
     constraint = semNodeKindConstraints(n, c.config, 1)
   elif n.kind == nkCall and
       n[0].kind in {nkIdent, nkSym, nkOpenSymChoice, nkClosedSymChoice} and
@@ -1119,7 +1117,7 @@ proc newProcType(c: PContext; info: TLineInfo; prev: PType = nil): PType =
   # result.n[0] used to be `nkType`, but now it's `nkEffectList` because
   # the effects are now stored in there too ... this is a bit hacky, but as
   # usual we desperately try to save memory:
-  addSon(result.n, newNodeI(nkEffectList, info))
+  result.n.add newNodeI(nkEffectList, info)
 
 proc semProcTypeNode(c: PContext, n, genericParams: PNode,
                      prev: PType, kind: TSymKind; isType=false): PType =
@@ -1130,8 +1128,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
   var check = initIntSet()
   var counter = 0
 
-  for i in 1 ..< n.len:
-    var a = n.sons[i]
+  for i in 1..<n.len:
+    var a = n[i]
     if a.kind != nkIdentDefs:
       # for some generic instantiations the passed ':env' parameter
       # for closures has already been produced (see bug #898). We simply
@@ -1145,17 +1143,16 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       typ: PType = nil
       def: PNode = nil
       constraint: PNode = nil
-      length = len(a)
-      hasType = a.sons[length-2].kind != nkEmpty
-      hasDefault = a.sons[length-1].kind != nkEmpty
+      hasType = a[^2].kind != nkEmpty
+      hasDefault = a[^1].kind != nkEmpty
 
     if hasType:
-      typ = semParamType(c, a.sons[length-2], constraint)
+      typ = semParamType(c, a[^2], constraint)
       var owner = getCurrOwner(c).owner
       # TODO: Disallow typed/untyped in procs in the compiler/stdlib
       if (owner.kind != skModule or owner.owner.name.s != "stdlib") and
         kind == skProc and (typ.kind == tyTyped or typ.kind == tyUntyped):
-          localError(c.config, a.sons[length-2].info, "'" & typ.sym.name.s & "' is only allowed in templates and macros")
+          localError(c.config, a[^2].info, "'" & typ.sym.name.s & "' is only allowed in templates and macros")
 
     if hasDefault:
       def = a[^1]
@@ -1203,8 +1200,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
     elif skipTypes(typ, {tyGenericInst, tyAlias, tySink}).kind == tyVoid:
       continue
 
-    for j in 0 .. length-3:
-      var arg = newSymG(skParam, a.sons[j], c)
+    for j in 0..<a.len-2:
+      var arg = newSymG(skParam, a[j], c)
       if not hasType and not hasDefault and kind notin {skTemplate, skMacro}:
         let param = strTableGet(c.signatures, arg.name)
         if param != nil: typ = param.typ
@@ -1221,22 +1218,22 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       if def != nil and def.kind != nkEmpty:
         arg.ast = copyTree(def)
       if containsOrIncl(check, arg.name.id):
-        localError(c.config, a.sons[j].info, "attempt to redefine: '" & arg.name.s & "'")
-      addSon(result.n, newSymNode(arg))
+        localError(c.config, a[j].info, "attempt to redefine: '" & arg.name.s & "'")
+      result.n.add newSymNode(arg)
       rawAddSon(result, finalType)
       addParamOrResult(c, arg, kind)
-      styleCheckDef(c.config, a.sons[j].info, arg)
+      styleCheckDef(c.config, a[j].info, arg)
       onDef(a[j].info, arg)
 
   var r: PType
-  if n.sons[0].kind != nkEmpty:
-    r = semTypeNode(c, n.sons[0], nil)
+  if n[0].kind != nkEmpty:
+    r = semTypeNode(c, n[0], nil)
 
   if r != nil and kind in {skMacro, skTemplate} and r.kind == tyTyped:
     # XXX: To implement the propesed change in the warning, just
     # delete this entire if block. The rest is (at least at time of
     # writing this comment) already implemented.
-    let info = n.sons[0].info
+    let info = n[0].info
     const msg = "`typed` will change its meaning in future versions of Nim. " &
                 "`void` or no return type declaration at all has the same " &
                 "meaning as the current meaning of `typed` as return type " &
@@ -1249,7 +1246,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
     # compiler only checks for 'nil':
     if skipTypes(r, {tyGenericInst, tyAlias, tySink}).kind != tyVoid:
       if kind notin {skMacro, skTemplate} and r.kind in {tyTyped, tyUntyped}:
-        localError(c.config, n.sons[0].info, "return type '" & typeToString(r) &
+        localError(c.config, n[0].info, "return type '" & typeToString(r) &
             "' is only valid for macros and templates")
       # 'auto' as a return type does not imply a generic:
       elif r.kind == tyAnything:
@@ -1262,7 +1259,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       else:
         if r.sym == nil or sfAnon notin r.sym.flags:
           let lifted = liftParamType(c, kind, genericParams, r, "result",
-                                     n.sons[0].info)
+                                     n[0].info)
           if lifted != nil:
             r = lifted
             #if r.kind != tyGenericParam:
@@ -1275,7 +1272,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
           # we don't need to change the return type to iter[T]
           result.flags.incl tfIterator
           # XXX Would be nice if we could get rid of this
-      result.sons[0] = r
+      result[0] = r
       let oldFlags = result.flags
       propagateToOwner(result, r)
       if oldFlags != result.flags:
@@ -1295,13 +1292,12 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
 
 proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
   checkMinSonsLen(n, 1, c.config)
-  var length = len(n)
-  for i in 0 .. length - 2:
-    n.sons[i] = semStmt(c, n.sons[i], {})
-  if length > 0:
-    result = semTypeNode(c, n.sons[length - 1], prev)
+  for i in 0..<n.len - 1:
+    n[i] = semStmt(c, n[i], {})
+  if n.len > 0:
+    result = semTypeNode(c, n[^1], prev)
     n.typ = result
-    n.sons[length - 1].typ = result
+    n[^1].typ = result
   else:
     result = nil
 
@@ -1309,10 +1305,10 @@ proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
   inc(c.p.nestedBlockCounter)
   checkSonsLen(n, 2, c.config)
   openScope(c)
-  if n.sons[0].kind notin {nkEmpty, nkSym}:
-    addDecl(c, newSymS(skLabel, n.sons[0], c))
-  result = semStmtListType(c, n.sons[1], prev)
-  n.sons[1].typ = result
+  if n[0].kind notin {nkEmpty, nkSym}:
+    addDecl(c, newSymS(skLabel, n[0], c))
+  result = semStmtListType(c, n[1], prev)
+  n[1].typ = result
   n.typ = result
   closeScope(c)
   dec(c.p.nestedBlockCounter)
@@ -1326,7 +1322,7 @@ proc semObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType) =
     check = initIntSet()
     pos = 0
   let
-    realBase = t.sons[0]
+    realBase = t[0]
     base = skipTypesOrNil(realBase, skipPtrs)
   if base.isNil:
     localError(c.config, n.info, errIllegalRecursionInTypeX % "object")
@@ -1360,8 +1356,8 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
     else: addSonSkipIntLit(result, typ)
 
   if t.kind == tyForward:
-    for i in 1 ..< len(n):
-      var elem = semGenericParamInInvocation(c, n.sons[i])
+    for i in 1..<n.len:
+      var elem = semGenericParamInInvocation(c, n[i])
       addToResult(elem)
     return
   elif t.kind != tyGenericBody:
@@ -1383,7 +1379,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
 
     var isConcrete = true
 
-    for i in 1 ..< m.call.len:
+    for i in 1..<m.call.len:
       var typ = m.call[i].typ
       # is this a 'typedesc' *parameter*? If so, use the typedesc type,
       # unstripped.
@@ -1412,7 +1408,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
     localError(c.config, n.info, "illegal recursion in type '$1'" % typeToString(result[0]))
     return errorType(c)
   if tx != result and tx.kind == tyObject:
-    if tx.sons[0] != nil:
+    if tx[0] != nil:
       semObjectTypeForInheritedGenericInst(c, n, tx)
     var position = 0
     recomputeFieldPositions(tx, tx.n, position)
@@ -1487,7 +1483,7 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
   if inherited.kind != nkEmpty:
     for n in inherited.sons:
       let typ = semTypeNode(c, n, nil)
-      result.sons.add(typ)
+      result.add(typ)
 
   openScope(c)
   for param in n[0]:
@@ -1525,15 +1521,15 @@ proc semProcTypeWithScope(c: PContext, n: PNode,
                         prev: PType, kind: TSymKind): PType =
   checkSonsLen(n, 2, c.config)
   openScope(c)
-  result = semProcTypeNode(c, n.sons[0], nil, prev, kind, isType=true)
+  result = semProcTypeNode(c, n[0], nil, prev, kind, isType=true)
   # start with 'ccClosure', but of course pragmas can overwrite this:
   result.callConv = ccClosure
   # dummy symbol for `pragma`:
   var s = newSymS(kind, newIdentNode(getIdent(c.cache, "dummy"), n.info), c)
   s.typ = result
-  if n.sons[1].kind != nkEmpty and n.sons[1].len > 0:
-    pragma(c, s, n.sons[1], procTypePragmas)
-    when useEffectSystem: setEffectsForProcType(c.graph, result, n.sons[1])
+  if n[1].kind != nkEmpty and n[1].len > 0:
+    pragma(c, s, n[1], procTypePragmas)
+    when useEffectSystem: setEffectsForProcType(c.graph, result, n[1])
   closeScope(c)
 
 proc symFromExpectedTypeNode(c: PContext, n: PNode): PSym =
@@ -1580,10 +1576,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   of nkTypeOfExpr:
     # for ``type(countup(1,3))``, see ``tests/ttoseq``.
     checkSonsLen(n, 1, c.config)
-    result = semTypeof(c, n.sons[0], prev)
+    result = semTypeof(c, n[0], prev)
     if result.kind == tyTypeDesc: result.flags.incl tfExplicit
   of nkPar:
-    if len(n) == 1: result = semTypeNode(c, n.sons[0], prev)
+    if n.len == 1: result = semTypeNode(c, n[0], prev)
     else:
       result = semAnonTuple(c, n, prev)
   of nkTupleConstr: result = semAnonTuple(c, n, prev)
@@ -1601,7 +1597,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
     elif ident != nil and ident.id == ord(wDotDot):
       result = semRangeAux(c, n, prev)
     elif n[0].kind == nkNilLit and n.len == 2:
-      result = semTypeNode(c, n.sons[1], prev)
+      result = semTypeNode(c, n[1], prev)
       if result.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).kind in NilableTypes+GenericTypes:
         if tfNotNil in result.flags:
           result = freshType(result, prev)
@@ -1611,17 +1607,17 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
     elif n[0].kind notin nkIdentKinds:
       result = semTypeExpr(c, n, prev)
     else:
-      let op = considerQuotedIdent(c, n.sons[0])
+      let op = considerQuotedIdent(c, n[0])
       if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
         checkSonsLen(n, 3, c.config)
         var
-          t1 = semTypeNode(c, n.sons[1], nil)
-          t2 = semTypeNode(c, n.sons[2], nil)
+          t1 = semTypeNode(c, n[1], nil)
+          t2 = semTypeNode(c, n[2], nil)
         if t1 == nil:
-          localError(c.config, n.sons[1].info, errTypeExpected)
+          localError(c.config, n[1].info, errTypeExpected)
           result = newOrPrevType(tyError, prev, c)
         elif t2 == nil:
-          localError(c.config, n.sons[2].info, errTypeExpected)
+          localError(c.config, n[2].info, errTypeExpected)
           result = newOrPrevType(tyError, prev, c)
         else:
           result = if op.id == ord(wAnd): makeAndType(c, t1, t2)
@@ -1629,9 +1625,9 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
       elif op.id == ord(wNot):
         case n.len
         of 3:
-          result = semTypeNode(c, n.sons[1], prev)
+          result = semTypeNode(c, n[1], prev)
           if result.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).kind in NilableTypes+GenericTypes+{tyForward} and
-              n.sons[2].kind == nkNilLit:
+              n[2].kind == nkNilLit:
             result = freshType(result, prev)
             result.flags.incl(tfNotNil)
             if notnil notin c.features:
@@ -1639,7 +1635,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
           else:
             localError(c.config, n.info, errGenerated, "invalid type")
         of 2:
-          let negated = semTypeNode(c, n.sons[1], prev)
+          let negated = semTypeNode(c, n[1], prev)
           result = makeNotType(c, negated)
         else:
           localError(c.config, n.info, errGenerated, "invalid type")
@@ -1665,7 +1661,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
     result = semTypeNode(c, whenResult, prev)
   of nkBracketExpr:
     checkMinSonsLen(n, 2, c.config)
-    var head = n.sons[0]
+    var head = n[0]
     var s = if head.kind notin nkCallKinds: semTypeIdent(c, head)
             else: symFromExpectedTypeNode(c, semExpr(c, head))
     case s.magic
@@ -1687,20 +1683,20 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
     of mStatic:
       result = semStaticType(c, n[1], prev)
     of mExpr:
-      result = semTypeNode(c, n.sons[0], nil)
+      result = semTypeNode(c, n[0], nil)
       if result != nil:
         result = copyType(result, getCurrOwner(c), false)
-        for i in 1 ..< n.len:
-          result.rawAddSon(semTypeNode(c, n.sons[i], nil))
+        for i in 1..<n.len:
+          result.rawAddSon(semTypeNode(c, n[i], nil))
     of mDistinct:
       result = newOrPrevType(tyDistinct, prev, c)
       addSonSkipIntLit(result, semTypeNode(c, n[1], nil))
     of mVar:
       result = newOrPrevType(tyVar, prev, c)
-      var base = semTypeNode(c, n.sons[1], nil)
+      var base = semTypeNode(c, n[1], nil)
       if base.kind in {tyVar, tyLent}:
         localError(c.config, n.info, "type 'var var' is not allowed")
-        base = base.sons[0]
+        base = base[0]
       addSonSkipIntLit(result, base)
     of mRef: result = semAnyRef(c, n, tyRef, prev)
     of mPtr: result = semAnyRef(c, n, tyPtr, prev)
@@ -1928,10 +1924,9 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
   if n.kind != nkGenericParams:
     illFormedAst(n, c.config)
     return
-  for i in 0 ..< len(n):
-    var a = n.sons[i]
+  for i in 0..<n.len:
+    var a = n[i]
     if a.kind != nkIdentDefs: illFormedAst(n, c.config)
-    let L = a.len
     var def = a[^1]
     let constraint = a[^2]
     var typ: PType
@@ -1940,7 +1935,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
       typ = semTypeNode(c, constraint, nil)
       if typ.kind != tyStatic or typ.len == 0:
         if typ.kind == tyTypeDesc:
-          if typ.sons[0].kind == tyNone:
+          if typ[0].kind == tyNone:
             typ = newTypeWithSons(c, tyTypeDesc, @[newTypeS(tyNone, c)])
             incl typ.flags, tfCheckedForDestructor
         else:
@@ -1964,14 +1959,14 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
 
     typ.flags.incl tfGenericTypeParam
 
-    for j in 0 .. L-3:
+    for j in 0..<a.len-2:
       let finalType = if j == 0: typ
                       else: copyType(typ, typ.owner, false)
                       # it's important the we create an unique
                       # type for each generic param. the index
                       # of the parameter will be stored in the
                       # attached symbol.
-      var paramName = a.sons[j]
+      var paramName = a[j]
       var covarianceFlag = tfUnresolved
 
       if paramName.safeLen == 2:
@@ -1992,5 +1987,5 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
       if def.kind != nkEmpty: s.ast = def
       if father != nil: addSonSkipIntLit(father, s.typ)
       s.position = result.len
-      addSon(result, newSymNode(s))
+      result.add newSymNode(s)
       if sfGenSym notin s.flags: addDecl(c, s)
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index f9908f90f..786a9e4f8 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -16,32 +16,32 @@ const
   tfInstClearedFlags = {tfHasMeta, tfUnresolved}
 
 proc checkPartialConstructedType(conf: ConfigRef; info: TLineInfo, t: PType) =
-  if t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}:
+  if t.kind in {tyVar, tyLent} and t[0].kind in {tyVar, tyLent}:
     localError(conf, info, "type 'var var' is not allowed")
 
 proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) =
   var t = typ.skipTypes({tyDistinct})
   if t.kind in tyTypeClasses: discard
-  elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}:
+  elif t.kind in {tyVar, tyLent} and t[0].kind in {tyVar, tyLent}:
     localError(conf, info, "type 'var var' is not allowed")
   elif computeSize(conf, t) == szIllegalRecursion or isTupleRecursive(t):
     localError(conf, info,  "illegal recursion in type '" & typeToString(t) & "'")
   when false:
-    if t.kind == tyObject and t.sons[0] != nil:
-      if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
+    if t.kind == tyObject and t[0] != nil:
+      if t[0].kind != tyObject or tfFinal in t[0].flags:
         localError(info, errInheritanceOnlyWithNonFinalObjects)
 
 proc searchInstTypes*(key: PType): PType =
-  let genericTyp = key.sons[0]
+  let genericTyp = key[0]
   if not (genericTyp.kind == tyGenericBody and
-      key.sons[0] == genericTyp and genericTyp.sym != nil): return
+      key[0] == genericTyp and genericTyp.sym != nil): return
 
   when not defined(nimNoNilSeqs):
     if genericTyp.sym.typeInstCache == nil: return
 
   for inst in genericTyp.sym.typeInstCache:
     if inst.id == key.id: return inst
-    if inst.sons.len < key.sons.len:
+    if inst.len < key.len:
       # XXX: This happens for prematurely cached
       # types such as Channel[empty]. Why?
       # See the notes for PActor in handleGenericInvocation
@@ -50,9 +50,9 @@ proc searchInstTypes*(key: PType): PType =
       continue
 
     block matchType:
-      for j in 1 .. high(key.sons):
+      for j in 1..high(key.sons):
         # XXX sameType is not really correct for nested generics?
-        if not compareTypes(inst.sons[j], key.sons[j],
+        if not compareTypes(inst[j], key[j],
                             flags = {ExactGenericParams}):
           break matchType
 
@@ -61,7 +61,7 @@ proc searchInstTypes*(key: PType): PType =
 proc cacheTypeInst*(inst: PType) =
   # XXX: add to module's generics
   #      update the refcount
-  let gt = inst.sons[0]
+  let gt = inst[0]
   let t = if gt.kind == tyGenericBody: gt.lastSon else: gt
   if t.kind in {tyStatic, tyError, tyGenericParam} + tyTypeClasses:
     return
@@ -129,7 +129,7 @@ proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
   result.typ = t
   if result.kind == nkSym: result.sym = replaceTypeVarsS(cl, n.sym)
   let isCall = result.kind in nkCallKinds
-  for i in 0 ..< n.safeLen:
+  for i in 0..<n.safeLen:
     # XXX HACK: ``f(a, b)``, avoid to instantiate `f`
     if isCall and i == 0: result.add(n[i])
     else: result.add(prepareNode(cl, n[i]))
@@ -151,14 +151,14 @@ proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode =
   # overload resolution is executed again (which may trigger generateInstance).
   if n.kind in nkCallKinds and sfFromGeneric in n[0].sym.flags:
     var needsFixing = false
-    for i in 1 ..< n.safeLen:
+    for i in 1..<n.safeLen:
       if isTypeParam(n[i]): needsFixing = true
     if needsFixing:
-      n.sons[0] = newSymNode(n.sons[0].sym.owner)
+      n[0] = newSymNode(n[0].sym.owner)
       return cl.c.semOverloadedCall(cl.c, n, n, {skProc, skFunc}, {})
 
-  for i in 0 ..< n.safeLen:
-    n.sons[i] = reResolveCallsWithTypedescParams(cl, n[i])
+  for i in 0..<n.safeLen:
+    n[i] = reResolveCallsWithTypedescParams(cl, n[i])
 
   return n
 
@@ -169,20 +169,20 @@ proc replaceObjBranches(cl: TReplTypeVars, n: PNode): PNode =
     discard
   of nkRecWhen:
     var branch: PNode = nil              # the branch to take
-    for i in 0 ..< len(n):
-      var it = n.sons[i]
+    for i in 0..<n.len:
+      var it = n[i]
       if it == nil: illFormedAst(n, cl.c.config)
       case it.kind
       of nkElifBranch:
         checkSonsLen(it, 2, cl.c.config)
-        var cond = it.sons[0]
+        var cond = it[0]
         var e = cl.c.semConstExpr(cl.c, cond)
         if e.kind != nkIntLit:
           internalError(cl.c.config, e.info, "ReplaceTypeVarsN: when condition not a bool")
-        if e.intVal != 0 and branch == nil: branch = it.sons[1]
+        if e.intVal != 0 and branch == nil: branch = it[1]
       of nkElse:
         checkSonsLen(it, 1, cl.c.config)
-        if branch == nil: branch = it.sons[0]
+        if branch == nil: branch = it[0]
       else: illFormedAst(n, cl.c.config)
     if branch != nil:
       result = replaceObjBranches(cl, branch)
@@ -190,7 +190,7 @@ proc replaceObjBranches(cl: TReplTypeVars, n: PNode): PNode =
       result = newNodeI(nkRecList, n.info)
   else:
     for i in 0..<n.len:
-      n.sons[i] = replaceObjBranches(cl, n.sons[i])
+      n[i] = replaceObjBranches(cl, n[i])
 
 proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode =
   if n == nil: return
@@ -209,20 +209,20 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode =
       result = newNode(nkRecList, n.info)
   of nkRecWhen:
     var branch: PNode = nil              # the branch to take
-    for i in 0 ..< len(n):
-      var it = n.sons[i]
+    for i in 0..<n.len:
+      var it = n[i]
       if it == nil: illFormedAst(n, cl.c.config)
       case it.kind
       of nkElifBranch:
         checkSonsLen(it, 2, cl.c.config)
-        var cond = prepareNode(cl, it.sons[0])
+        var cond = prepareNode(cl, it[0])
         var e = cl.c.semConstExpr(cl.c, cond)
         if e.kind != nkIntLit:
           internalError(cl.c.config, e.info, "ReplaceTypeVarsN: when condition not a bool")
-        if e.intVal != 0 and branch == nil: branch = it.sons[1]
+        if e.intVal != 0 and branch == nil: branch = it[1]
       of nkElse:
         checkSonsLen(it, 1, cl.c.config)
-        if branch == nil: branch = it.sons[0]
+        if branch == nil: branch = it[0]
       else: illFormedAst(n, cl.c.config)
     if branch != nil:
       result = replaceTypeVarsN(cl, branch)
@@ -234,13 +234,12 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode =
     result = if cl.allowMetaTypes: n
              else: cl.c.semExpr(cl.c, n)
   else:
-    var length = len(n)
-    if length > 0:
-      newSons(result, length)
+    if n.len > 0:
+      newSons(result, n.len)
       if start > 0:
-        result.sons[0] = n.sons[0]
-      for i in start ..< length:
-        result.sons[i] = replaceTypeVarsN(cl, n.sons[i])
+        result[0] = n[0]
+      for i in start..<n.len:
+        result[i] = replaceTypeVarsN(cl, n[i])
 
 proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
   if s == nil: return nil
@@ -317,7 +316,7 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
 proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
   # tyGenericInvocation[A, tyGenericInvocation[A, B]]
   # is difficult to handle:
-  var body = t.sons[0]
+  var body = t[0]
   if body.kind != tyGenericBody:
     internalError(cl.c.config, cl.info, "no generic body")
   var header: PType = t
@@ -331,13 +330,13 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
     when defined(reportCacheHits):
       echo "Generic instantiation cached ", typeToString(result), " for ", typeToString(t)
     return
-  for i in 1 ..< len(t):
-    var x = t.sons[i]
+  for i in 1..<t.len:
+    var x = t[i]
     if x.kind in {tyGenericParam}:
       x = lookupTypeVar(cl, x)
       if x != nil:
         if header == t: header = instCopyType(cl, t)
-        header.sons[i] = x
+        header[i] = x
         propagateToOwner(header, x)
     else:
       propagateToOwner(header, x)
@@ -353,10 +352,10 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
   else:
     header = instCopyType(cl, t)
 
-  result = newType(tyGenericInst, t.sons[0].owner)
+  result = newType(tyGenericInst, t[0].owner)
   result.flags = header.flags
   # be careful not to propagate unnecessary flags here (don't use rawAddSon)
-  result.sons = @[header.sons[0]]
+  result.sons = @[header[0]]
   # ugh need another pass for deeply recursive generic types (e.g. PActor)
   # we need to add the candidate here, before it's fully instantiated for
   # recursive instantions:
@@ -371,17 +370,17 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
   var typeMapLayer = newTypeMapLayer(cl)
   cl.typeMap = addr(typeMapLayer)
 
-  for i in 1 ..< len(t):
-    var x = replaceTypeVarsT(cl, t.sons[i])
+  for i in 1..<t.len:
+    var x = replaceTypeVarsT(cl, t[i])
     assert x.kind != tyGenericInvocation
-    header.sons[i] = x
+    header[i] = x
     propagateToOwner(header, x)
-    cl.typeMap.put(body.sons[i-1], x)
+    cl.typeMap.put(body[i-1], x)
 
-  for i in 1 ..< len(t):
+  for i in 1..<t.len:
     # if one of the params is not concrete, we cannot do anything
     # but we already raised an error!
-    rawAddSon(result, header.sons[i])
+    rawAddSon(result, header[i])
 
   if body.kind == tyError:
     return
@@ -443,35 +442,35 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
 proc eraseVoidParams*(t: PType) =
   # transform '(): void' into '()' because old parts of the compiler really
   # don't deal with '(): void':
-  if t.sons[0] != nil and t.sons[0].kind == tyVoid:
-    t.sons[0] = nil
+  if t[0] != nil and t[0].kind == tyVoid:
+    t[0] = nil
 
-  for i in 1 ..< t.len:
+  for i in 1..<t.len:
     # don't touch any memory unless necessary
-    if t.sons[i].kind == tyVoid:
+    if t[i].kind == tyVoid:
       var pos = i
-      for j in i+1 ..< t.len:
-        if t.sons[j].kind != tyVoid:
-          t.sons[pos] = t.sons[j]
-          t.n.sons[pos] = t.n.sons[j]
+      for j in i+1..<t.len:
+        if t[j].kind != tyVoid:
+          t[pos] = t[j]
+          t.n[pos] = t.n[j]
           inc pos
       setLen t.sons, pos
       setLen t.n.sons, pos
       break
 
 proc skipIntLiteralParams*(t: PType) =
-  for i in 0 ..< t.len:
-    let p = t.sons[i]
+  for i in 0..<t.len:
+    let p = t[i]
     if p == nil: continue
     let skipped = p.skipIntLit
     if skipped != p:
-      t.sons[i] = skipped
-      if i > 0: t.n.sons[i].sym.typ = skipped
+      t[i] = skipped
+      if i > 0: t.n[i].sym.typ = skipped
 
   # when the typeof operator is used on a static input
   # param, the results gets infected with static as well:
-  if t.sons[0] != nil and t.sons[0].kind == tyStatic:
-    t.sons[0] = t.sons[0].base
+  if t[0] != nil and t[0].kind == tyStatic:
+    t[0] = t[0].base
 
 proc propagateFieldFlags(t: PType, n: PNode) =
   # This is meant for objects and tuples
@@ -563,8 +562,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
         result = makeTypeDesc(cl.c, result)
       elif tfUnresolved in t.flags or cl.skipTypedesc:
         result = result.base
-    elif t.sons[0].kind != tyNone:
-      result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.sons[0]))
+    elif t[0].kind != tyNone:
+      result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t[0]))
 
   of tyUserTypeClass, tyStatic:
     result = t
@@ -573,8 +572,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
     bailout()
     result = instCopyType(cl, t)
     idTablePut(cl.localCache, t, result)
-    for i in 1 ..< result.len:
-      result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
+    for i in 1..<result.len:
+      result[i] = replaceTypeVarsT(cl, result[i])
     propagateToOwner(result, result.lastSon)
 
   else:
@@ -586,28 +585,28 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
       #if not cl.allowMetaTypes:
       idTablePut(cl.localCache, t, result)
 
-      for i in 0 ..< len(result):
-        if result.sons[i] != nil:
-          if result.sons[i].kind == tyGenericBody:
+      for i in 0..<result.len:
+        if result[i] != nil:
+          if result[i].kind == tyGenericBody:
             localError(cl.c.config, if t.sym != nil: t.sym.info else: cl.info,
               "cannot instantiate '" &
-              typeToString(result.sons[i], preferDesc) &
+              typeToString(result[i], preferDesc) &
               "' inside of type definition: '" &
               t.owner.name.s & "'; Maybe generic arguments are missing?")
-          var r = replaceTypeVarsT(cl, result.sons[i])
+          var r = replaceTypeVarsT(cl, result[i])
           if result.kind == tyObject:
             # carefully coded to not skip the precious tyGenericInst:
             let r2 = r.skipTypes({tyAlias, tySink, tyOwned})
             if r2.kind in {tyPtr, tyRef}:
               r = skipTypes(r2, {tyPtr, tyRef})
-          result.sons[i] = r
+          result[i] = r
           if result.kind != tyArray or i != 0:
             propagateToOwner(result, r)
       # bug #4677: Do not instantiate effect lists
       result.n = replaceTypeVarsN(cl, result.n, ord(result.kind==tyProc))
       case result.kind
       of tyArray:
-        let idx = result.sons[0]
+        let idx = result[0]
         internalAssert cl.c.config, idx.kind != tyStatic
 
       of tyObject, tyTuple:
@@ -674,16 +673,16 @@ proc replaceTypesForLambda*(p: PContext, pt: TIdTable, n: PNode;
   popInfoContext(p.config)
 
 proc recomputeFieldPositions*(t: PType; obj: PNode; currPosition: var int) =
-  if t != nil and t.len > 0 and t.sons[0] != nil:
-    let b = skipTypes(t.sons[0], skipPtrs)
+  if t != nil and t.len > 0 and t[0] != nil:
+    let b = skipTypes(t[0], skipPtrs)
     recomputeFieldPositions(b, b.n, currPosition)
   case obj.kind
   of nkRecList:
-    for i in 0 ..< len(obj): recomputeFieldPositions(nil, obj.sons[i], currPosition)
+    for i in 0..<obj.len: recomputeFieldPositions(nil, obj[i], currPosition)
   of nkRecCase:
-    recomputeFieldPositions(nil, obj.sons[0], currPosition)
-    for i in 1 ..< len(obj):
-      recomputeFieldPositions(nil, lastSon(obj.sons[i]), currPosition)
+    recomputeFieldPositions(nil, obj[0], currPosition)
+    for i in 1..<obj.len:
+      recomputeFieldPositions(nil, lastSon(obj[i]), currPosition)
   of nkSym:
     obj.sym.position = currPosition
     inc currPosition
diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim
index 90b7001a5..f94cd5bce 100644
--- a/compiler/sighashes.nim
+++ b/compiler/sighashes.nim
@@ -84,7 +84,7 @@ proc hashTree(c: var MD5Context, n: PNode) =
   of nkStrLit..nkTripleStrLit:
     c &= n.strVal
   else:
-    for i in 0..<n.len: hashTree(c, n.sons[i])
+    for i in 0..<n.len: hashTree(c, n[i])
 
 proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
   if t == nil:
@@ -93,8 +93,8 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
 
   case t.kind
   of tyGenericInvocation:
-    for i in 0 ..< len(t):
-      c.hashType t.sons[i], flags
+    for i in 0..<t.len:
+      c.hashType t[i], flags
   of tyDistinct:
     if CoDistinct in flags:
       if t.sym != nil: c.hashSym(t.sym)
@@ -110,8 +110,8 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
       # We cannot trust the `lastSon` to hold a properly populated and unique
       # value for each instantiation, so we hash the generic parameters here:
       let normalizedType = t.skipGenericAlias
-      for i in 0 .. normalizedType.len - 2:
-        c.hashType t.sons[i], flags
+      for i in 0..<normalizedType.len - 1:
+        c.hashType t[i], flags
     else:
       c.hashType t.lastSon, flags
   of tyAlias, tySink, tyUserTypeClasses, tyInferred:
@@ -132,8 +132,8 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
       let inst = t.typeInst
       t.typeInst = nil
       assert inst.kind == tyGenericInst
-      for i in 0 .. inst.len - 2:
-        c.hashType inst.sons[i], flags
+      for i in 0..<inst.len - 1:
+        c.hashType inst[i], flags
       t.typeInst = inst
       return
     c &= char(t.kind)
@@ -168,8 +168,8 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
           c &= ".empty"
     else:
       c &= t.id
-    if t.len > 0 and t.sons[0] != nil:
-      hashType c, t.sons[0], flags
+    if t.len > 0 and t[0] != nil:
+      hashType c, t[0], flags
   of tyRef, tyPtr, tyGenericBody, tyVar:
     c &= char(t.kind)
     c.hashType t.lastSon, flags
@@ -180,24 +180,24 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
   of tyTuple:
     c &= char(t.kind)
     if t.n != nil and CoType notin flags:
-      assert(len(t.n) == len(t))
-      for i in 0 ..< len(t.n):
-        assert(t.n.sons[i].kind == nkSym)
-        c &= t.n.sons[i].sym.name.s
+      assert(t.n.len == t.len)
+      for i in 0..<t.n.len:
+        assert(t.n[i].kind == nkSym)
+        c &= t.n[i].sym.name.s
         c &= ':'
-        c.hashType(t.sons[i], flags+{CoIgnoreRange})
+        c.hashType(t[i], flags+{CoIgnoreRange})
         c &= ','
     else:
-      for i in 0 ..< len(t): c.hashType t.sons[i], flags+{CoIgnoreRange}
+      for i in 0..<t.len: c.hashType t[i], flags+{CoIgnoreRange}
   of tyRange:
     if CoIgnoreRange notin flags:
       c &= char(t.kind)
       c.hashTree(t.n)
-    c.hashType(t.sons[0], flags)
+    c.hashType(t[0], flags)
   of tyStatic:
     c &= char(t.kind)
     c.hashTree(t.n)
-    c.hashType(t.sons[0], flags)
+    c.hashType(t[0], flags)
   of tyProc:
     c &= char(t.kind)
     c &= (if tfIterator in t.flags: "iterator " else: "proc ")
@@ -209,9 +209,9 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
         c &= ':'
         c.hashType(param.typ, flags)
         c &= ','
-      c.hashType(t.sons[0], flags)
+      c.hashType(t[0], flags)
     else:
-      for i in 0..<t.len: c.hashType(t.sons[i], flags)
+      for i in 0..<t.len: c.hashType(t[i], flags)
     c &= char(t.callConv)
     # purity of functions doesn't have to affect the mangling (which is in fact
     # problematic for HCR - someone could have cached a pointer to another
@@ -223,10 +223,10 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
     if tfVarargs in t.flags: c &= ".varargs"
   of tyArray:
     c &= char(t.kind)
-    for i in 0..<t.len: c.hashType(t.sons[i], flags-{CoIgnoreRange})
+    for i in 0..<t.len: c.hashType(t[i], flags-{CoIgnoreRange})
   else:
     c &= char(t.kind)
-    for i in 0..<t.len: c.hashType(t.sons[i], flags)
+    for i in 0..<t.len: c.hashType(t[i], flags)
   if tfNotNil in t.flags and CoType notin flags: c &= "not nil"
 
 when defined(debugSigHashes):
@@ -352,7 +352,7 @@ proc hashBodyTree(graph: ModuleGraph, c: var MD5Context, n: PNode) =
     c &= n.strVal
   else:
     for i in 0..<n.len:
-      hashBodyTree(graph, c, n.sons[i])
+      hashBodyTree(graph, c, n[i])
 
 proc symBodyDigest*(graph: ModuleGraph, sym: PSym): SigHash =
   ## compute unique digest of the proc/func/method symbols
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index c3245ca1a..8b829cec9 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -167,8 +167,8 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
   initIdTable(c.bindings)
   if binding != nil and callee.kind in routineKinds:
     var typeParams = callee.ast[genericParamsPos]
-    for i in 1..min(len(typeParams), len(binding)-1):
-      var formalTypeParam = typeParams.sons[i-1].typ
+    for i in 1..min(typeParams.len, binding.len-1):
+      var formalTypeParam = typeParams[i-1].typ
       var bound = binding[i].typ
       if bound != nil:
         if formalTypeParam.kind == tyTypeDesc:
@@ -220,7 +220,7 @@ proc sumGeneric(t: PType): int =
       inc result, maxBranch
       break
     of tyVar:
-      t = t.sons[0]
+      t = t[0]
       inc result
       inc isvar
     of tyTypeDesc:
@@ -229,12 +229,12 @@ proc sumGeneric(t: PType): int =
       inc result
     of tyGenericInvocation, tyTuple, tyProc, tyAnd:
       result += ord(t.kind in {tyGenericInvocation, tyAnd})
-      for i in 0 ..< t.len:
-        if t.sons[i] != nil:
-          result += sumGeneric(t.sons[i])
+      for i in 0..<t.len:
+        if t[i] != nil:
+          result += sumGeneric(t[i])
       break
     of tyStatic:
-      return sumGeneric(t.sons[0]) + 1
+      return sumGeneric(t[0]) + 1
     of tyGenericParam, tyUntyped, tyTyped: break
     of tyAlias, tySink: t = t.lastSon
     of tyBool, tyChar, tyEnum, tyObject, tyPointer,
@@ -249,12 +249,12 @@ proc sumGeneric(t: PType): int =
 proc complexDisambiguation(a, b: PType): int =
   # '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
+  for i in 1..<min(a.len, b.len):
+    let x = a[i].sumGeneric
+    let y = b[i].sumGeneric
     #if ggDebug:
-    #echo "came herA ", typeToString(a.sons[i]), " ", x
-    #echo "came herB ", typeToString(b.sons[i]), " ", y
+    #echo "came herA ", typeToString(a[i]), " ", x
+    #echo "came herB ", typeToString(b[i]), " ", y
     if x != y:
       if winner == 0:
         if x > y: winner = 1
@@ -269,8 +269,8 @@ proc complexDisambiguation(a, b: PType): int =
   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
+    for i in 1..<a.len: x += a[i].sumGeneric
+    for i in 1..<b.len: y += b[i].sumGeneric
     result = x - y
 
 proc writeMatches*(c: TCandidate) =
@@ -305,7 +305,7 @@ proc cmpCandidates*(a, b: TCandidate): int =
 proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
   if arg.kind in nkSymChoices:
     result = typeToString(arg[0].typ, prefer)
-    for i in 1 ..< arg.len:
+    for i in 1..<arg.len:
       result.add(" | ")
       result.add typeToString(arg[i].typ, prefer)
   elif arg.typ == nil:
@@ -316,25 +316,25 @@ proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
 proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
                    prefer: TPreferedDesc = preferName): string =
   result = ""
-  for i in startIdx ..< n.len:
-    var arg = n.sons[i]
-    if n.sons[i].kind == nkExprEqExpr:
-      add(result, renderTree(n.sons[i].sons[0]))
-      add(result, ": ")
+  for i in startIdx..<n.len:
+    var arg = n[i]
+    if n[i].kind == nkExprEqExpr:
+      result.add(renderTree(n[i][0]))
+      result.add(": ")
       if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo}:
         # XXX we really need to 'tryExpr' here!
-        arg = c.semOperand(c, n.sons[i].sons[1])
-        n.sons[i].typ = arg.typ
-        n.sons[i].sons[1] = arg
+        arg = c.semOperand(c, n[i][1])
+        n[i].typ = arg.typ
+        n[i][1] = arg
     else:
       if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo, nkElse,
                                            nkOfBranch, nkElifBranch,
                                            nkExceptBranch}:
-        arg = c.semOperand(c, n.sons[i])
-        n.sons[i] = arg
+        arg = c.semOperand(c, n[i])
+        n[i] = arg
     if arg.typ != nil and arg.typ.kind == tyError: return
-    add(result, argTypeToString(arg, prefer))
-    if i != len(n) - 1: add(result, ", ")
+    result.add(argTypeToString(arg, prefer))
+    if i != n.len - 1: result.add(", ")
 
 proc typeRel*(c: var TCandidate, f, aOrig: PType,
               flags: TTypeRelFlags = {}): TTypeRelation
@@ -345,7 +345,7 @@ proc concreteType(c: TCandidate, t: PType; f: PType = nil): PType =
     if c.isNoCall: result = t
     else: result = nil
   of tySequence, tySet:
-    if t.sons[0].kind == tyEmpty: result = nil
+    if t[0].kind == tyEmpty: result = nil
     else: result = t
   of tyGenericParam, tyAnything:
     result = t
@@ -362,7 +362,7 @@ proc concreteType(c: TCandidate, t: PType; f: PType = nil): PType =
   of tyOwned:
     # bug #11257: the comparison system.`==`[T: proc](x, y: T) works
     # better without the 'owned' type:
-    if f != nil and f.len > 0 and f.sons[0].skipTypes({tyBuiltInTypeClass}).kind == tyProc:
+    if f != nil and f.len > 0 and f[0].skipTypes({tyBuiltInTypeClass}).kind == tyProc:
       result = t.lastSon
     else:
       result = t
@@ -440,10 +440,10 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
 proc genericParamPut(c: var TCandidate; last, fGenericOrigin: PType) =
   if fGenericOrigin != nil and last.kind == tyGenericInst and
      last.len-1 == fGenericOrigin.len:
-    for i in 1 ..< len(fGenericOrigin):
-      let x = PType(idTableGet(c.bindings, fGenericOrigin.sons[i]))
+    for i in 1..<fGenericOrigin.len:
+      let x = PType(idTableGet(c.bindings, fGenericOrigin[i]))
       if x == nil:
-        put(c, fGenericOrigin.sons[i], last.sons[i])
+        put(c, fGenericOrigin[i], last[i])
 
 proc isObjectSubtype(c: var TCandidate; a, f, fGenericOrigin: PType): int =
   var t = a
@@ -452,7 +452,7 @@ proc isObjectSubtype(c: var TCandidate; a, f, fGenericOrigin: PType): int =
   var last = a
   while t != nil and not sameObjectTypes(f, t):
     assert t.kind == tyObject
-    t = t.sons[0]
+    t = t[0]
     if t == nil: break
     last = t
     t = skipTypes(t, skipPtrs)
@@ -473,7 +473,7 @@ proc skipToObject(t: PType; skipped: var SkippedPtr): PType =
   while r != nil:
     case r.kind
     of tyGenericInvocation:
-      r = r.sons[0]
+      r = r[0]
     of tyRef:
       inc ptrs
       skipped = skippedRef
@@ -500,7 +500,7 @@ proc isGenericSubtype(c: var TCandidate; a, f: PType, d: var int, fGenericOrigin
   # XXX sameObjectType can return false here. Need to investigate
   # why that is but sameObjectType does way too much work here anyway.
   while t != nil and r.sym != t.sym and askip == fskip:
-    t = t.sons[0]
+    t = t[0]
     if t == nil: break
     last = t
     t = t.skipToObject(askip)
@@ -518,22 +518,22 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
   result = isNone
   if sameType(f, a):
     result = isEqual
-  elif len(a) == len(f):
+  elif a.len == f.len:
     result = isEqual
     let firstField = if f.kind == tyTuple: 0
                      else: 1
-    for i in firstField ..< len(f):
-      var m = typeRel(c, f.sons[i], a.sons[i])
+    for i in firstField..<f.len:
+      var m = typeRel(c, f[i], a[i])
       if m < isSubtype: return isNone
       result = minRel(result, m)
     if f.n != nil and a.n != nil:
-      for i in 0 ..< len(f.n):
+      for i in 0..<f.n.len:
         # check field names:
-        if f.n.sons[i].kind != nkSym: return isNone
-        elif a.n.sons[i].kind != nkSym: return isNone
+        if f.n[i].kind != nkSym: return isNone
+        elif a.n[i].kind != nkSym: return isNone
         else:
-          var x = f.n.sons[i].sym
-          var y = a.n.sons[i].sym
+          var x = f.n[i].sym
+          var y = a.n[i].sym
           if f.kind == tyObject and typeRel(c, x.typ, y.typ) < isSubtype:
             return isNone
           if x.name.id != y.name.id: return isNone
@@ -552,7 +552,7 @@ proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
 
 proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   ## For example we have:
-  ## .. code-block:: nim
+  ##..code-block:: nim
   ##   proc myMap[T,S](sIn: seq[T], f: proc(x: T): S): seq[S] = ...
   ##   proc innerProc[Q,W](q: Q): W = ...
   ## And we want to match: myMap(@[1,2,3], innerProc)
@@ -607,7 +607,7 @@ proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
 proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   case a.kind
   of tyProc:
-    if len(f) != len(a): return
+    if f.len != a.len: return
     result = isEqual      # start with maximum; also correct for no
                           # params at all
 
@@ -617,15 +617,15 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
 
     # Note: We have to do unification for the parameters before the
     # return type!
-    for i in 1 ..< f.len:
-      checkParam(f.sons[i], a.sons[i])
+    for i in 1..<f.len:
+      checkParam(f[i], a[i])
 
-    if f.sons[0] != nil:
-      if a.sons[0] != nil:
-        checkParam(f.sons[0], a.sons[0])
+    if f[0] != nil:
+      if a[0] != nil:
+        checkParam(f[0], a[0])
       else:
         return isNone
-    elif a.sons[0] != nil:
+    elif a[0] != nil:
       return isNone
 
     if tfNoSideEffect in f.flags and tfNoSideEffect notin a.flags:
@@ -687,20 +687,20 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
 
   openScope(c)
   matchedConceptContext.candidateType = a
-  typeClass[0].sons[0] = a
+  typeClass[0][0] = a
   c.matchedConcept = addr(matchedConceptContext)
   defer:
     c.matchedConcept = prevMatchedConcept
-    typeClass[0].sons[0] = prevCandidateType
+    typeClass[0][0] = prevCandidateType
     closeScope(c)
 
   var typeParams: seq[(PSym, PType)]
 
   if ff.kind == tyUserTypeClassInst:
-    for i in 1 ..< (ff.len - 1):
+    for i in 1..<(ff.len - 1):
       var
-        typeParamName = ff.base.sons[i-1].sym.name
-        typ = ff.sons[i]
+        typeParamName = ff.base[i-1].sym.name
+        typ = ff[i]
         param: PSym
         alreadyBound = PType(idTableGet(m.bindings, typ))
 
@@ -944,8 +944,8 @@ proc isCovariantPtr(c: var TCandidate, f, a: PType): bool =
     let body = f.base
     return body == a.base and
            a.len == 3 and
-           tfWeakCovariant notin body.sons[0].flags and
-           baseTypesCheck(f.sons[1], a.sons[1])
+           tfWeakCovariant notin body[0].flags and
+           baseTypesCheck(f[1], a[1])
   else:
     return false
 
@@ -1038,7 +1038,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
       result = typeRel(c, aOrig.base, candidate)
       if result != isNone:
         c.inferredTypes.add aOrig
-        aOrig.sons.add candidate
+        aOrig.add candidate
         result = isEqual
       return
 
@@ -1146,7 +1146,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
         # that may appear in the range:
         for i in 0..1:
           if f.n[i].kind == nkStaticExpr:
-            f.n.sons[i] = tryResolvingStaticExpr(c, f.n[i])
+            f.n[i] = tryResolvingStaticExpr(c, f.n[i])
         result = typeRangeRel(f, a)
     else:
       if skipTypes(f, {tyRange}).kind == a.kind:
@@ -1174,20 +1174,20 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
   of tyArray:
     case a.kind
     of tyArray:
-      var fRange = f.sons[0]
-      var aRange = a.sons[0]
+      var fRange = f[0]
+      var aRange = a[0]
       if fRange.kind == tyGenericParam:
         var prev = PType(idTableGet(c.bindings, fRange))
         if prev == nil:
-          put(c, fRange, a.sons[0])
+          put(c, fRange, a[0])
           fRange = a
         else:
           fRange = prev
-      let ff = f.sons[1].skipTypes({tyTypeDesc})
+      let ff = f[1].skipTypes({tyTypeDesc})
       # This typeDesc rule is wrong, see bug #7331
-      let aa = a.sons[1] #.skipTypes({tyTypeDesc})
+      let aa = a[1] #.skipTypes({tyTypeDesc})
 
-      if f.sons[0].kind != tyGenericParam and aa.kind == tyEmpty:
+      if f[0].kind != tyGenericParam and aa.kind == tyEmpty:
         result = isGeneric
       else:
         result = typeRel(c, ff, aa)
@@ -1220,7 +1220,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
     if f.kind == tyVarargs:
       if tfVarargs in a.flags:
         return typeRel(c, f.base, a.lastSon)
-      if f.sons[0].kind == tyTyped: return
+      if f[0].kind == tyTyped: return
 
     template matchArrayOrSeq(aBase: PType) =
       let ff = f.base
@@ -1239,29 +1239,29 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
       result = typeRel(c, base(f), base(a))
       if result < isGeneric: result = isNone
     of tyArray:
-      if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
+      if (f[0].kind != tyGenericParam) and (a[1].kind == tyEmpty):
         return isSubtype
-      matchArrayOrSeq(a.sons[1])
+      matchArrayOrSeq(a[1])
     of tySequence:
-      if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
+      if (f[0].kind != tyGenericParam) and (a[0].kind == tyEmpty):
         return isConvertible
-      matchArrayOrSeq(a.sons[0])
+      matchArrayOrSeq(a[0])
     of tyString:
       if f.kind == tyOpenArray:
-        if f.sons[0].kind == tyChar:
+        if f[0].kind == tyChar:
           result = isConvertible
-        elif f.sons[0].kind == tyGenericParam and a.len > 0 and
+        elif f[0].kind == tyGenericParam and a.len > 0 and
             typeRel(c, base(f), base(a)) >= isGeneric:
           result = isConvertible
     else: discard
   of tySequence:
     case a.kind
     of tySequence:
-      if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
+      if (f[0].kind != tyGenericParam) and (a[0].kind == tyEmpty):
         result = isSubtype
       else:
-        let ff = f.sons[0]
-        let aa = a.sons[0]
+        let ff = f[0]
+        let aa = a[0]
         result = typeRel(c, ff, aa)
         if result < isGeneric:
           if nimEnableCovariance and
@@ -1277,11 +1277,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
     else: discard
   of tyOrdinal:
     if isOrdinalType(a):
-      var x = if a.kind == tyOrdinal: a.sons[0] else: a
-      if f.sons[0].kind == tyNone:
+      var x = if a.kind == tyOrdinal: a[0] else: a
+      if f[0].kind == tyNone:
         result = isGeneric
       else:
-        result = typeRel(c, f.sons[0], x)
+        result = typeRel(c, f[0], x)
         if result < isGeneric: result = isNone
     elif a.kind == tyGenericParam:
       result = isGeneric
@@ -1314,10 +1314,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
     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:
+      if f[0].kind != tyGenericParam and a[0].kind == tyEmpty:
         result = isSubtype
       else:
-        result = typeRel(c, f.sons[0], a.sons[0])
+        result = typeRel(c, f[0], a[0])
         if result <= isConvertible:
           result = isNone     # BUGFIX!
   of tyPtr, tyRef:
@@ -1325,8 +1325,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
     if a.kind == f.kind:
       # ptr[R, T] can be passed to ptr[T], but not the other way round:
       if a.len < f.len: return isNone
-      for i in 0..f.len-2:
-        if typeRel(c, f.sons[i], a.sons[i]) == isNone: return isNone
+      for i in 0..<f.len-1:
+        if typeRel(c, f[i], a[i]) == isNone: return isNone
       result = typeRel(c, f.lastSon, a.lastSon, flags + {trNoCovariance})
       subtypeCheck()
       if result <= isIntConv: result = isNone
@@ -1384,13 +1384,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
     of tyPtr:
       # ptr[Tag, char] is not convertible to 'cstring' for now:
       if a.len == 1:
-        let pointsTo = a.sons[0].skipTypes(abstractInst)
+        let pointsTo = a[0].skipTypes(abstractInst)
         if pointsTo.kind == tyChar: result = isConvertible
-        elif pointsTo.kind == tyUncheckedArray and pointsTo.sons[0].kind == tyChar:
+        elif pointsTo.kind == tyUncheckedArray and pointsTo[0].kind == tyChar:
           result = isConvertible
-        elif pointsTo.kind == tyArray and firstOrd(nil, pointsTo.sons[0]) == 0 and
-            skipTypes(pointsTo.sons[0], {tyRange}).kind in {tyInt..tyInt64} and
-            pointsTo.sons[1].kind == tyChar:
+        elif pointsTo.kind == tyArray and firstOrd(nil, pointsTo[0]) == 0 and
+            skipTypes(pointsTo[0], {tyRange}).kind in {tyInt..tyInt64} and
+            pointsTo[1].kind == tyChar:
           result = isConvertible
     else: discard
 
@@ -1416,14 +1416,14 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
         # YYYY
         result = isEqual
 
-        for i in 1 .. rootf.len-2:
-          let ff = rootf.sons[i]
-          let aa = roota.sons[i]
+        for i in 1..<rootf.len-1:
+          let ff = rootf[i]
+          let aa = roota[i]
           let res = typeRel(c, ff, aa, nextFlags)
           if res != isEqual: result = isGeneric
           if res notin {isEqual, isGeneric}:
             if trNoCovariance notin flags and ff.kind == aa.kind:
-              let paramFlags = rootf.base.sons[i-1].flags
+              let paramFlags = rootf.base[i-1].flags
               hasCovariance =
                 if tfCovariant in paramFlags:
                   if tfWeakCovariant in paramFlags:
@@ -1471,7 +1471,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
 
   of tyGenericBody:
     considerPreviousT:
-      if a == f or a.kind == tyGenericInst and a.sons[0] == f:
+      if a == f or a.kind == tyGenericInst and a[0] == f:
         bindingRet isGeneric
       let ff = lastSon(f)
       if ff != nil:
@@ -1480,7 +1480,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
   of tyGenericInvocation:
     var x = a.skipGenericAlias
     var preventHack = false
-    if x.kind == tyOwned and f.sons[0].kind != tyOwned:
+    if x.kind == tyOwned and f[0].kind != tyOwned:
       preventHack = true
       x = x.lastSon
     # XXX: This is very hacky. It should be moved back into liftTypeParam
@@ -1492,21 +1492,21 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
       return typeRel(c, inst, a)
 
     var depth = 0
-    if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody:
+    if x.kind == tyGenericInvocation or f[0].kind != tyGenericBody:
       #InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
       # simply no match for now:
       discard
-    elif x.kind == tyGenericInst and f.sons[0] == x.sons[0] and
-          len(x) - 1 == len(f):
-      for i in 1 ..< len(f):
-        if x.sons[i].kind == tyGenericParam:
+    elif x.kind == tyGenericInst and f[0] == x[0] and
+          x.len - 1 == f.len:
+      for i in 1..<f.len:
+        if x[i].kind == tyGenericParam:
           internalError(c.c.graph.config, "wrong instantiated type!")
-        elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype:
+        elif typeRel(c, f[i], x[i]) <= isSubtype:
           # Workaround for regression #4589
-          if f.sons[i].kind != tyTypeDesc: return
+          if f[i].kind != tyTypeDesc: return
       result = isGeneric
     elif x.kind == tyGenericInst and isGenericSubtype(c, x, f, depth, f) and
-          (len(x) - 1 == len(f)):
+          (x.len - 1 == f.len):
       # do not recurse here in order to not K bind twice for this code:
       #
       # type
@@ -1518,7 +1518,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
       c.inheritancePenalty += depth
       result = isGeneric
     else:
-      let genericBody = f.sons[0]
+      let genericBody = f[0]
       var askip = skippedNone
       var fskip = skippedNone
       let aobj = x.skipToObject(askip)
@@ -1538,14 +1538,14 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
         # var it1 = internalFind(root, 312) # cannot instantiate: 'D'
         #
         # we steal the generic parameters from the tyGenericBody:
-        for i in 1 ..< len(f):
-          let x = PType(idTableGet(c.bindings, genericBody.sons[i-1]))
+        for i in 1..<f.len:
+          let x = PType(idTableGet(c.bindings, genericBody[i-1]))
           if x == nil:
             discard "maybe fine (for eg. a==tyNil)"
           elif x.kind in {tyGenericInvocation, tyGenericParam}:
             internalError(c.c.graph.config, "wrong instantiated type!")
           else:
-            let key = f.sons[i]
+            let key = f[i]
             let old = PType(idTableGet(c.bindings, key))
             if old == nil:
               put(c, key, x)
@@ -1612,7 +1612,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
 
   of tyBuiltInTypeClass:
     considerPreviousT:
-      let targetKind = f.sons[0].kind
+      let targetKind = f[0].kind
       let effectiveArgType = a.skipTypes({tyRange, tyGenericInst,
                                           tyBuiltInTypeClass, tyAlias, tySink, tyOwned})
       let typeClassMatches = targetKind == effectiveArgType.kind and
@@ -1643,9 +1643,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
       let roota = a.skipGenericAlias
       let rootf = f.lastSon.skipGenericAlias
       if a.kind == tyGenericInst and roota.base == rootf.base:
-        for i in 1 .. rootf.len-2:
-          let ff = rootf.sons[i]
-          let aa = roota.sons[i]
+        for i in 1..<rootf.len-1:
+          let ff = rootf[i]
+          let aa = roota[i]
           result = typeRel(c, ff, aa)
           if result == isNone: return
           if ff.kind == tyRange and result != isEqual: return isNone
@@ -1689,9 +1689,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
           result = isNone
       else:
         # check if 'T' has a constraint as in 'proc p[T: Constraint](x: T)'
-        if f.len > 0 and f.sons[0].kind != tyNone:
+        if f.len > 0 and f[0].kind != tyNone:
           let oldInheritancePenalty = c.inheritancePenalty
-          result = typeRel(c, f.sons[0], a, flags + {trDontBind})
+          result = typeRel(c, f[0], a, flags + {trDontBind})
           if doBind and result notin {isNone, isGeneric}:
             let concrete = concreteType(c, a, f)
             if concrete == nil: return isNone
@@ -1772,7 +1772,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
       result = typeRel(c, f.base, a)
       if result != isNone:
         c.inferredTypes.add f
-        f.sons.add a
+        f.add a
 
   of tyTypeDesc:
     var prev = PType(idTableGet(c.bindings, f))
@@ -1846,8 +1846,7 @@ when false:
       echo f, " <- ", aOrig, " res ", result
 
 proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
-  var m: TCandidate
-  initCandidate(c, m, f)
+  var m = newCandidate(c, f)
   result = typeRel(m, f, a)
 
 proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate,
@@ -1870,15 +1869,15 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
   else:
     result.typ = f
   if result.typ == nil: internalError(c.graph.config, arg.info, "implicitConv")
-  addSon(result, c.graph.emptyNode)
-  addSon(result, arg)
+  result.add c.graph.emptyNode
+  result.add arg
 
 proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
                    arg: PNode): PNode =
   result = nil
-  for i in 0 ..< len(c.converters):
-    var src = c.converters[i].typ.sons[1]
-    var dest = c.converters[i].typ.sons[0]
+  for i in 0..<c.converters.len:
+    var src = c.converters[i].typ[1]
+    var dest = c.converters[i].typ[0]
     # for generic type converters we need to check 'src <- a' before
     # 'f <- dest' in order to not break the unification:
     # see tests/tgenericconverter:
@@ -1902,7 +1901,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
       s.typ = c.converters[i].typ
       s.info = arg.info
       result = newNodeIT(nkHiddenCallConv, arg.info, dest)
-      addSon(result, s)
+      result.add s
       # We build the call expression by ourselves in order to avoid passing this
       # expression trough the semantic check phase once again so let's make sure
       # it is correct
@@ -1912,10 +1911,10 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
       elif src.kind == tyVar:
         # Analyse the converter return type
         param = newNodeIT(nkHiddenAddr, arg.info, s.typ[1])
-        param.addSon(copyTree(arg))
+        param.add copyTree(arg)
       else:
         param = copyTree(arg)
-      addSon(result, param)
+      result.add param
 
       if dest.kind in {tyVar, tyLent}:
         dest.flags.incl tfVarIsPtr
@@ -1942,7 +1941,7 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
   if result != nil:
     if result.typ == nil: return nil
     # resulting type must be consistent with the other arguments:
-    var r = typeRel(m, f.sons[0], result.typ)
+    var r = typeRel(m, f[0], result.typ)
     if r < isGeneric: return nil
     if result.kind == nkCall: result.kind = nkHiddenCallConv
     inc(m.convMatches)
@@ -1962,8 +1961,8 @@ proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
   of isNone: discard
 
 template matchesVoidProc(t: PType): bool =
-  (t.kind == tyProc and t.len == 1 and t.sons[0] == nil) or
-    (t.kind == tyBuiltInTypeClass and t.sons[0].kind == tyProc)
+  (t.kind == tyProc and t.len == 1 and t[0] == nil) or
+    (t.kind == tyBuiltInTypeClass and t[0].kind == tyProc)
 
 proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
                         argSemantized, argOrig: PNode): PNode =
@@ -2174,31 +2173,31 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
     # this correctly is inefficient. We have to copy `m` here to be able to
     # roll back the side effects of the unification algorithm.
     let c = m.c
-    var x, y, z: TCandidate
-    initCandidate(c, x, m.callee)
-    initCandidate(c, y, m.callee)
-    initCandidate(c, z, m.callee)
+    var
+      x = newCandidate(c, m.callee)
+      y = newCandidate(c, m.callee)
+      z = newCandidate(c, m.callee)
     x.calleeSym = m.calleeSym
     y.calleeSym = m.calleeSym
     z.calleeSym = m.calleeSym
     var best = -1
-    for i in 0 ..< arg.len:
-      if arg.sons[i].sym.kind in {skProc, skFunc, skMethod, skConverter,
+    for i in 0..<arg.len:
+      if arg[i].sym.kind in {skProc, skFunc, skMethod, skConverter,
                                   skIterator, skMacro, skTemplate}:
         copyCandidate(z, m)
-        z.callee = arg.sons[i].typ
+        z.callee = arg[i].typ
         if tfUnresolved in z.callee.flags: continue
-        z.calleeSym = arg.sons[i].sym
-        #if arg.sons[i].sym.name.s == "cmp":
+        z.calleeSym = arg[i].sym
+        #if arg[i].sym.name.s == "cmp":
         #  ggDebug = true
         #  echo "CALLLEEEEEEEE A ", typeToString(z.callee)
         # XXX this is still all wrong: (T, T) should be 2 generic matches
         # and  (int, int) 2 exact matches, etc. Essentially you cannot call
         # typeRel here and expect things to work!
-        let r = typeRel(z, f, arg.sons[i].typ)
+        let r = typeRel(z, f, arg[i].typ)
         incMatches(z, r, 2)
-        #if arg.sons[i].sym.name.s == "cmp": # and arg.info.line == 606:
-        #  echo "M ", r, " ", arg.info, " ", typeToString(arg.sons[i].sym.typ)
+        #if arg[i].sym.name.s == "cmp": # and arg.info.line == 606:
+        #  echo "M ", r, " ", arg.info, " ", typeToString(arg[i].sym.typ)
         #  writeMatches(z)
         if r != isNone:
           z.state = csMatch
@@ -2226,10 +2225,9 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
       else: result = nil
     else:
       # only one valid interpretation found:
-      markUsed(m.c, arg.info, arg.sons[best].sym)
-      onUse(arg.info, arg.sons[best].sym)
-      result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
-                                  argOrig)
+      markUsed(m.c, arg.info, arg[best].sym)
+      onUse(arg.info, arg[best].sym)
+      result = paramTypesMatchAux(m, f, arg[best].typ, arg[best], argOrig)
   when false:
     if m.calleeSym != nil and m.calleeSym.name.s == "[]":
       echo m.c.config $ arg.info, " for ", m.calleeSym.name.s, " ", m.c.config $ m.calleeSym.info
@@ -2239,10 +2237,10 @@ proc setSon(father: PNode, at: int, son: PNode) =
   let oldLen = father.len
   if oldLen <= at:
     setLen(father.sons, at + 1)
-  father.sons[at] = son
+  father[at] = son
   # insert potential 'void' parameters:
-  #for i in oldLen ..< at:
-  #  father.sons[i] = newNodeIT(nkEmpty, son.info, getSysType(tyVoid))
+  #for i in oldLen..<at:
+  #  father[i] = newNodeIT(nkEmpty, son.info, getSysType(tyVoid))
 
 # we are allowed to modify the calling node in the 'prepare*' procs:
 proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode =
@@ -2271,9 +2269,9 @@ proc prepareOperand(c: PContext; a: PNode): PNode =
     considerGenSyms(c, result)
 
 proc prepareNamedParam(a: PNode; c: PContext) =
-  if a.sons[0].kind != nkIdent:
-    var info = a.sons[0].info
-    a.sons[0] = newIdentNode(considerQuotedIdent(c, a.sons[0]), info)
+  if a[0].kind != nkIdent:
+    var info = a[0].info
+    a[0] = newIdentNode(considerQuotedIdent(c, a[0]), info)
 
 proc arrayConstr(c: PContext, n: PNode): PType =
   result = newTypeS(tyArray, c)
@@ -2288,10 +2286,10 @@ proc arrayConstr(c: PContext, info: TLineInfo): PType =
 
 proc incrIndexType(t: PType) =
   assert t.kind == tyArray
-  inc t.sons[0].n.sons[1].intVal
+  inc t[0].n[1].intVal
 
 template isVarargsUntyped(x): untyped =
-  x.kind == tyVarargs and x.sons[0].kind == tyUntyped
+  x.kind == tyVarargs and x[0].kind == tyUntyped
 
 proc matchesAux(c: PContext, n, nOrig: PNode,
                 m: var TCandidate, marker: var IntSet) =
@@ -2333,37 +2331,37 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
   m.call = newNodeI(n.kind, n.info)
   m.call.typ = base(m.callee) # may be nil
   var formalLen = m.callee.n.len
-  addSon(m.call, n.sons[0])
+  m.call.add n[0]
   var container: PNode = nil # constructed container
-  formal = if formalLen > 1: m.callee.n.sons[1].sym else: nil
+  formal = if formalLen > 1: m.callee.n[1].sym else: nil
 
   while a < n.len:
     if a >= formalLen-1 and f < formalLen and m.callee.n[f].typ.isVarargsUntyped:
-      formal = m.callee.n.sons[f].sym
+      formal = m.callee.n[f].sym
       incl(marker, formal.position)
 
-      if n.sons[a].kind == nkHiddenStdConv:
-        doAssert n.sons[a].sons[0].kind == nkEmpty and
-                 n.sons[a].sons[1].kind in {nkBracket, nkArgList}
+      if n[a].kind == nkHiddenStdConv:
+        doAssert n[a][0].kind == nkEmpty and
+                 n[a][1].kind in {nkBracket, nkArgList}
         # Steal the container and pass it along
-        setSon(m.call, formal.position + 1, n.sons[a].sons[1])
+        setSon(m.call, formal.position + 1, n[a][1])
       else:
         if container.isNil:
-          container = newNodeIT(nkArgList, n.sons[a].info, arrayConstr(c, n.info))
+          container = newNodeIT(nkArgList, n[a].info, arrayConstr(c, n.info))
           setSon(m.call, formal.position + 1, container)
         else:
           incrIndexType(container.typ)
-        addSon(container, n.sons[a])
-    elif n.sons[a].kind == nkExprEqExpr:
+        container.add n[a]
+    elif n[a].kind == nkExprEqExpr:
       # named param
       m.firstMismatch.kind = kUnknownNamedParam
       # check if m.callee has such a param:
-      prepareNamedParam(n.sons[a], c)
-      if n.sons[a].sons[0].kind != nkIdent:
-        localError(c.config, n.sons[a].info, "named parameter has to be an identifier")
+      prepareNamedParam(n[a], c)
+      if n[a][0].kind != nkIdent:
+        localError(c.config, n[a].info, "named parameter has to be an identifier")
         noMatch()
         return
-      formal = getNamedParamFromList(m.callee.n, n.sons[a].sons[0].ident)
+      formal = getNamedParamFromList(m.callee.n, n[a][0].ident)
       if formal == nil:
         # no error message!
         noMatch()
@@ -2374,24 +2372,24 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
         # we used to produce 'errCannotBindXTwice' here but see
         # bug #3836 of why that is not sound (other overload with
         # different parameter names could match later on):
-        when false: localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
+        when false: localError(n[a].info, errCannotBindXTwice, formal.name.s)
         noMatch()
         return
       m.baseTypeMatch = false
       m.typedescMatched = 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
-      arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
-                                n.sons[a].sons[1], n.sons[a].sons[1])
+      n[a][1] = prepareOperand(c, formal.typ, n[a][1])
+      n[a].typ = n[a][1].typ
+      arg = paramTypesMatch(m, formal.typ, n[a].typ,
+                                n[a][1], n[a][1])
       m.firstMismatch.kind = kTypeMismatch
       if arg == nil:
         noMatch()
         return
-      checkConstraint(n.sons[a].sons[1])
+      checkConstraint(n[a][1])
       if m.baseTypeMatch:
         #assert(container == nil)
-        container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
-        addSon(container, arg)
+        container = newNodeIT(nkBracket, n[a].info, arrayConstr(c, arg))
+        container.add arg
         setSon(m.call, formal.position + 1, container)
         if f != formalLen - 1: container = nil
       else:
@@ -2404,13 +2402,13 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
         if tfVarargs in m.callee.flags:
           # is ok... but don't increment any counters...
           # we have no formal here to snoop at:
-          n.sons[a] = prepareOperand(c, n.sons[a])
-          if skipTypes(n.sons[a].typ, abstractVar-{tyTypeDesc}).kind==tyString:
-            addSon(m.call, implicitConv(nkHiddenStdConv,
-                  getSysType(c.graph, n.sons[a].info, tyCString),
-                  copyTree(n.sons[a]), m, c))
+          n[a] = prepareOperand(c, n[a])
+          if skipTypes(n[a].typ, abstractVar-{tyTypeDesc}).kind==tyString:
+            m.call.add implicitConv(nkHiddenStdConv,
+                  getSysType(c.graph, n[a].info, tyCString),
+                  copyTree(n[a]), m, c)
           else:
-            addSon(m.call, copyTree(n.sons[a]))
+            m.call.add copyTree(n[a])
         elif formal != nil and formal.typ.kind == tyVarargs:
           m.firstMismatch.kind = kTypeMismatch
           # beware of the side-effects in 'prepareOperand'! So only do it for
@@ -2418,13 +2416,13 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           m.baseTypeMatch = false
           m.typedescMatched = false
           incl(marker, formal.position)
-          n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
-          arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
-                                    n.sons[a], nOrig.sons[a])
+          n[a] = prepareOperand(c, formal.typ, n[a])
+          arg = paramTypesMatch(m, formal.typ, n[a].typ,
+                                    n[a], nOrig[a])
           if arg != nil and m.baseTypeMatch and container != nil:
-            addSon(container, arg)
+            container.add arg
             incrIndexType(container.typ)
-            checkConstraint(n.sons[a])
+            checkConstraint(n[a])
           else:
             noMatch()
             return
@@ -2433,32 +2431,32 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           noMatch()
           return
       else:
-        if m.callee.n.sons[f].kind != nkSym:
-          internalError(c.config, n.sons[a].info, "matches")
+        if m.callee.n[f].kind != nkSym:
+          internalError(c.config, n[a].info, "matches")
           noMatch()
           return
-        formal = m.callee.n.sons[f].sym
+        formal = m.callee.n[f].sym
         m.firstMismatch.kind = kTypeMismatch
         if containsOrIncl(marker, formal.position) and container.isNil:
           m.firstMismatch.kind = kPositionalAlreadyGiven
           # positional param already in namedParams: (see above remark)
-          when false: localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
+          when false: localError(n[a].info, errCannotBindXTwice, formal.name.s)
           noMatch()
           return
 
         if formal.typ.isVarargsUntyped:
           if container.isNil:
-            container = newNodeIT(nkArgList, n.sons[a].info, arrayConstr(c, n.info))
+            container = newNodeIT(nkArgList, n[a].info, arrayConstr(c, n.info))
             setSon(m.call, formal.position + 1, container)
           else:
             incrIndexType(container.typ)
-          addSon(container, n.sons[a])
+          container.add n[a]
         else:
           m.baseTypeMatch = false
           m.typedescMatched = false
-          n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
-          arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
-                                    n.sons[a], nOrig.sons[a])
+          n[a] = prepareOperand(c, formal.typ, n[a])
+          arg = paramTypesMatch(m, formal.typ, n[a].typ,
+                                    n[a], nOrig[a])
           if arg == nil:
             noMatch()
             return
@@ -2466,11 +2464,11 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
             assert formal.typ.kind == tyVarargs
             #assert(container == nil)
             if container.isNil:
-              container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
+              container = newNodeIT(nkBracket, n[a].info, arrayConstr(c, arg))
               container.typ.flags.incl tfVarargs
             else:
               incrIndexType(container.typ)
-            addSon(container, arg)
+            container.add arg
             setSon(m.call, formal.position + 1,
                    implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
             #if f != formalLen - 1: container = nil
@@ -2487,11 +2485,11 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
             # a container
             #assert arg.kind == nkHiddenStdConv # for 'nim check'
             # this assertion can be off
-            localError(c.config, n.sons[a].info, "cannot convert $1 to $2" % [
-              typeToString(n.sons[a].typ), typeToString(formal.typ) ])
+            localError(c.config, n[a].info, "cannot convert $1 to $2" % [
+              typeToString(n[a].typ), typeToString(formal.typ) ])
             noMatch()
             return
-        checkConstraint(n.sons[a])
+        checkConstraint(n[a])
     inc(a)
   # for some edge cases (see tdont_return_unowned_from_owned test case)
   m.firstMismatch.arg = a
@@ -2500,8 +2498,8 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
 proc semFinishOperands*(c: PContext, n: PNode) =
   # this needs to be called to ensure that after overloading resolution every
   # argument has been sem'checked:
-  for i in 1 ..< n.len:
-    n.sons[i] = prepareOperand(c, n.sons[i])
+  for i in 1..<n.len:
+    n[i] = prepareOperand(c, n[i])
 
 proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
   # for 'suggest' support:
@@ -2522,9 +2520,8 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
   matchesAux(c, n, nOrig, m, marker)
   if m.state == csNoMatch: return
   # check that every formal parameter got a value:
-  var f = 1
-  while f < len(m.callee.n):
-    var formal = m.callee.n.sons[f].sym
+  for f in 1..<m.callee.n.len:
+    var formal = m.callee.n[f].sym
     if not containsOrIncl(marker, formal.position):
       if formal.ast == nil:
         if formal.typ.kind == tyVarargs:
@@ -2563,15 +2560,13 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
             put(m, formal.typ, defaultValue.typ)
         defaultValue.flags.incl nfDefaultParam
         setSon(m.call, formal.position + 1, defaultValue)
-    inc(f)
   # forget all inferred types if the overload matching failed
   if m.state == csNoMatch:
     for t in m.inferredTypes:
       if t.len > 1: t.sons.setLen 1
 
 proc argtypeMatches*(c: PContext, f, a: PType, fromHlo = false): bool =
-  var m: TCandidate
-  initCandidate(c, m, f)
+  var m = newCandidate(c, f)
   let res = paramTypesMatch(m, f, a, c.graph.emptyNode, nil)
   #instantiateGenericConverters(c, res, m)
   # XXX this is used by patterns.nim too; I think it's better to not
@@ -2583,13 +2578,12 @@ proc argtypeMatches*(c: PContext, f, a: PType, fromHlo = false): bool =
     res != nil and m.convMatches == 0 and m.intConvMatches in [0, 256]
 
 proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
-                      op: TTypeAttachedOp; col: int): PSym {.procvar.} =
-  var m: TCandidate
-  initCandidate(c, m, dc.typ)
+                      op: TTypeAttachedOp; col: int): PSym =
+  var m = newCandidate(c, dc.typ)
   if col >= dc.typ.len:
     localError(c.config, info, "cannot instantiate: '" & dc.name.s & "'")
     return nil
-  var f = dc.typ.sons[col]
+  var f = dc.typ[col]
 
   if op == attachedDeepCopy:
     if f.kind in {tyRef, tyPtr}: f = f.lastSon
@@ -2632,8 +2626,8 @@ tests:
     result = newType(tyArray, dummyOwner)
 
     var n = newNodeI(nkRange, UnknownLineInfo())
-    addSon(n, newIntNode(nkIntLit, 0))
-    addSon(n, newIntNode(nkIntLit, x))
+    n.add newIntNode(nkIntLit, 0)
+    n.add newIntNode(nkIntLit, x)
     let range = newType(tyRange, dummyOwner)
 
     result.rawAddSon(range)
@@ -2660,8 +2654,7 @@ tests:
     T2.sym.position = 1
 
     setup:
-      var c: TCandidate
-      initCandidate(nil, c, nil)
+      var c = newCandidate(nil, nil)
 
     template yes(x, y) =
       test astToStr(x) & " is " & astToStr(y):
diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim
index e6bd1fc7b..adbd02026 100644
--- a/compiler/sizealignoffsetimpl.nim
+++ b/compiler/sizealignoffsetimpl.nim
@@ -79,10 +79,10 @@ proc computeSubObjectAlign(conf: ConfigRef; n: PNode): BiggestInt =
   ## returns object alignment
   case n.kind
   of nkRecCase:
-    assert(n.sons[0].kind == nkSym)
-    result = computeSubObjectAlign(conf, n.sons[0])
-    for i in 1 ..< len(n):
-      let child = n.sons[i]
+    assert(n[0].kind == nkSym)
+    result = computeSubObjectAlign(conf, n[0])
+    for i in 1..<n.len:
+      let child = n[i]
       case child.kind
       of nkOfBranch, nkElse:
         let align = computeSubObjectAlign(conf, child.lastSon)
@@ -94,7 +94,7 @@ proc computeSubObjectAlign(conf: ConfigRef; n: PNode): BiggestInt =
   of nkRecList:
     result = 1
     for i, child in n.sons:
-      let align = computeSubObjectAlign(conf, n.sons[i])
+      let align = computeSubObjectAlign(conf, n[i])
       if align < 0:
         return align
       result = max(result, align)
@@ -109,7 +109,7 @@ proc setOffsetsToUnknown(n: PNode) =
   if n.kind == nkSym and n.sym.kind == skField:
     n.sym.offset = szUnknownSize
   else:
-    for i in 0 ..< safeLen(n):
+    for i in 0..<n.safeLen:
       setOffsetsToUnknown(n[i])
 
 proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, packed: bool, accum: var OffsetAccum) =
@@ -120,16 +120,16 @@ proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, packed: bool, a
     raiseIllegalTypeRecursion()
   case n.kind
   of nkRecCase:
-    assert(n.sons[0].kind == nkSym)
-    computeObjectOffsetsFoldFunction(conf, n.sons[0], packed, accum)
+    assert(n[0].kind == nkSym)
+    computeObjectOffsetsFoldFunction(conf, n[0], packed, accum)
     var maxChildAlign: int = if accum.offset == szUnknownSize: szUnknownSize else: 1
     if not packed:
-      for i in 1 ..< len(n):
-        let child = n.sons[i]
+      for i in 1..<n.len:
+        let child = n[i]
         case child.kind
         of nkOfBranch, nkElse:
           # offset parameter cannot be known yet, it needs to know the alignment first
-          let align = int(computeSubObjectAlign(conf, n.sons[i].lastSon))
+          let align = int(computeSubObjectAlign(conf, n[i].lastSon))
           maxChildAlign = alignmentMax(maxChildAlign, align)
         else:
           internalError(conf, "computeObjectOffsetsFoldFunction(record case branch)")
@@ -141,9 +141,9 @@ proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, packed: bool, a
       # the union neds to be aligned first, before the offsets can be assigned
       accum.align(maxChildAlign)
       let accumRoot = accum # copy, because each branch should start af the same offset
-      for i in 1 ..< len(n):
+      for i in 1..<n.len:
         var branchAccum = accumRoot
-        computeObjectOffsetsFoldFunction(conf, n.sons[i].lastSon, packed, branchAccum)
+        computeObjectOffsetsFoldFunction(conf, n[i].lastSon, packed, branchAccum)
         accum.mergeBranch(branchAccum)
   of nkRecList:
     for i, child in n.sons:
@@ -255,14 +255,14 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
       typ.size = conf.target.ptrSize
 
   of tyArray:
-    computeSizeAlign(conf, typ.sons[1])
-    let elemSize = typ.sons[1].size
+    computeSizeAlign(conf, typ[1])
+    let elemSize = typ[1].size
     if elemSize < 0:
       typ.size = elemSize
       typ.align = int16(elemSize)
     else:
-      typ.size = toInt64Checked(lengthOrd(conf, typ.sons[0]) * int32(elemSize), szTooBigSize)
-      typ.align = typ.sons[1].align
+      typ.size = toInt64Checked(lengthOrd(conf, typ[0]) * int32(elemSize), szTooBigSize)
+      typ.align = typ[1].align
 
   of tyUncheckedArray:
     let base = typ.lastSon
@@ -289,11 +289,11 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
         typ.size = 8
         typ.align = int16(conf.floatInt64Align)
   of tySet:
-    if typ.sons[0].kind == tyGenericParam:
+    if typ[0].kind == tyGenericParam:
       typ.size = szUncomputedSize
       typ.align = szUncomputedSize
     else:
-      let length = toInt64(lengthOrd(conf, typ.sons[0]))
+      let length = toInt64(lengthOrd(conf, typ[0]))
       if length <= 8:
         typ.size = 1
         typ.align = 1
@@ -313,16 +313,16 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
         typ.size = align(length, 8) div 8 + 1
         typ.align = int16(conf.floatInt64Align)
   of tyRange:
-    computeSizeAlign(conf, typ.sons[0])
-    typ.size = typ.sons[0].size
-    typ.align = typ.sons[0].align
-    typ.paddingAtEnd = typ.sons[0].paddingAtEnd
+    computeSizeAlign(conf, typ[0])
+    typ.size = typ[0].size
+    typ.align = typ[0].align
+    typ.paddingAtEnd = typ[0].paddingAtEnd
 
   of tyTuple:
     try:
       var accum = OffsetAccum(maxAlign: 1)
-      for i in 0 ..< len(typ):
-        let child = typ.sons[i]
+      for i in 0..<typ.len:
+        let child = typ[i]
         computeSizeAlign(conf, child)
         accum.align(child.align)
         if typ.n != nil: # is named tuple (has field symbols)?
@@ -340,11 +340,11 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
   of tyObject:
     try:
       var accum =
-        if typ.sons[0] != nil:
+        if typ[0] != nil:
           # compute header size
-          var st = typ.sons[0]
+          var st = typ[0]
           while st.kind in skipPtrs:
-            st = st.sons[^1]
+            st = st[^1]
           computeSizeAlign(conf, st)
           if conf.cmd == cmdCompileToCpp:
             OffsetAccum(
diff --git a/compiler/spawn.nim b/compiler/spawn.nim
index b48c67fd3..382237e70 100644
--- a/compiler/spawn.nim
+++ b/compiler/spawn.nim
@@ -16,7 +16,7 @@ from trees import getMagic
 proc callProc(a: PNode): PNode =
   result = newNodeI(nkCall, a.info)
   result.add a
-  result.typ = a.typ.sons[0]
+  result.typ = a.typ[0]
 
 # we have 4 cases to consider:
 # - a void proc --> nothing to do
@@ -60,18 +60,18 @@ proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; owner: PSym; typ: P
   incl(result.flags, sfFromGeneric)
 
   var vpart = newNodeI(nkIdentDefs, varSection.info, 3)
-  vpart.sons[0] = newSymNode(result)
-  vpart.sons[1] = newNodeI(nkEmpty, varSection.info)
-  vpart.sons[2] = if varInit.isNil: v else: vpart[1]
+  vpart[0] = newSymNode(result)
+  vpart[1] = newNodeI(nkEmpty, varSection.info)
+  vpart[2] = if varInit.isNil: v else: vpart[1]
   varSection.add vpart
   if varInit != nil:
     if useShallowCopy and typeNeedsNoDeepCopy(typ) or optTinyRtti in g.config.globalOptions:
       varInit.add newFastAsgnStmt(newSymNode(result), v)
     else:
       let deepCopyCall = newNodeI(nkCall, varInit.info, 3)
-      deepCopyCall.sons[0] = newSymNode(getSysMagic(g, varSection.info, "deepCopy", mDeepCopy))
-      deepCopyCall.sons[1] = newSymNode(result)
-      deepCopyCall.sons[2] = v
+      deepCopyCall[0] = newSymNode(getSysMagic(g, varSection.info, "deepCopy", mDeepCopy))
+      deepCopyCall[1] = newSymNode(result)
+      deepCopyCall[2] = v
       varInit.add deepCopyCall
 
 discard """
@@ -137,16 +137,16 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
   if spawnKind == srByVar:
     body.add newAsgnStmt(genDeref(threadLocalProm.newSymNode), call)
   elif fv != nil:
-    let fk = fv.typ.sons[1].flowVarKind
+    let fk = fv.typ[1].flowVarKind
     if fk == fvInvalid:
       localError(g.config, f.info, "cannot create a flowVar of type: " &
-        typeToString(fv.typ.sons[1]))
+        typeToString(fv.typ[1]))
     body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
       if fk == fvGC: "data" else: "blob", fv.info, g.cache), call)
     if fk == fvGC:
       let incRefCall = newNodeI(nkCall, fv.info, 2)
-      incRefCall.sons[0] = newSymNode(getSysMagic(g, fv.info, "GCref", mGCref))
-      incRefCall.sons[1] = indirectAccess(threadLocalProm.newSymNode,
+      incRefCall[0] = newSymNode(getSysMagic(g, fv.info, "GCref", mGCref))
+      incRefCall[1] = indirectAccess(threadLocalProm.newSymNode,
                                           "data", fv.info, g.cache)
       body.add incRefCall
     if barrier == nil:
@@ -196,7 +196,7 @@ proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; scratchOb
                              varSection, varInit, result: PNode) =
   let formals = n[0].typ.n
   let tmpName = getIdent(g.cache, genPrefix)
-  for i in 1 ..< n.len:
+  for i in 1..<n.len:
     # we pick n's type here, which hopefully is 'tyArray' and not
     # 'tyOpenArray':
     var argType = n[i].typ.skipTypes(abstractInst)
@@ -225,11 +225,11 @@ proc getRoot*(n: PNode): PSym =
       result = n.sym
   of nkDotExpr, nkBracketExpr, nkHiddenDeref, nkDerefExpr,
       nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
-    result = getRoot(n.sons[0])
+    result = getRoot(n[0])
   of nkHiddenStdConv, nkHiddenSubConv, nkConv:
-    result = getRoot(n.sons[1])
+    result = getRoot(n[1])
   of nkCallKinds:
-    if getMagic(n) == mSlice: result = getRoot(n.sons[1])
+    if getMagic(n) == mSlice: result = getRoot(n[1])
   else: discard
 
 proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchObj: PSym;
@@ -239,7 +239,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb
   let tmpName = getIdent(g.cache, genPrefix)
   # we need to copy the foreign scratch object fields into local variables
   # for correctness: These are called 'threadLocal' here.
-  for i in 1 ..< n.len:
+  for i in 1..<n.len:
     let n = n[i]
     let argType = skipTypes(if i < formals.len: formals[i].typ else: n.typ,
                             abstractInst)
@@ -253,8 +253,8 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb
       # important special case: we always create a zero-copy slice:
       let slice = newNodeI(nkCall, n.info, 4)
       slice.typ = n.typ
-      slice.sons[0] = newSymNode(createMagic(g, "slice", mSlice))
-      slice.sons[0].typ = getSysType(g, n.info, tyInt) # fake type
+      slice[0] = newSymNode(createMagic(g, "slice", mSlice))
+      slice[0].typ = getSysType(g, n.info, tyInt) # fake type
       var fieldB = newSym(skField, tmpName, objType.owner, n.info, g.config.options)
       fieldB.typ = getSysType(g, n.info, tyInt)
       objType.addField(fieldB, g.cache)
@@ -274,7 +274,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb
         let threadLocal = addLocalVar(g, varSection,nil, objType.owner, fieldA.typ,
                                       indirectAccess(castExpr, fieldA, n.info),
                                       useShallowCopy=true)
-        slice.sons[2] = threadLocal.newSymNode
+        slice[2] = threadLocal.newSymNode
       else:
         let a = genAddrOf(n)
         field.typ = a.typ
@@ -282,14 +282,14 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb
         result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
         result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), genHigh(g, n))
 
-        slice.sons[2] = newIntLit(g, n.info, 0)
+        slice[2] = newIntLit(g, n.info, 0)
       # the array itself does not need to go through a thread local variable:
-      slice.sons[1] = genDeref(indirectAccess(castExpr, field, n.info))
+      slice[1] = genDeref(indirectAccess(castExpr, field, n.info))
 
       let threadLocal = addLocalVar(g, varSection,nil, objType.owner, fieldB.typ,
                                     indirectAccess(castExpr, fieldB, n.info),
                                     useShallowCopy=true)
-      slice.sons[3] = threadLocal.newSymNode
+      slice[3] = threadLocal.newSymNode
       call.add slice
     elif (let size = computeSize(g.config, argType); size < 0 or size > 16) and
         n.getRoot != nil:
@@ -358,7 +358,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P
     result.add varSectionB
 
   var call = newNodeIT(nkCall, n.info, n.typ)
-  var fn = n.sons[0]
+  var fn = n[0]
   # templates and macros are in fact valid here due to the nature of
   # the transformation:
   if fn.kind == nkClosure or (fn.typ != nil and fn.typ.callConv == ccClosure):
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index 85761a8a9..11717c946 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -49,12 +49,12 @@ proc findDocComment(n: PNode): PNode =
   if n == nil: return nil
   if n.comment.len > 0: return n
   if n.kind in {nkStmtList, nkStmtListExpr, nkObjectTy, nkRecList} and n.len > 0:
-    result = findDocComment(n.sons[0])
+    result = findDocComment(n[0])
     if result != nil: return
     if n.len > 1:
-      result = findDocComment(n.sons[1])
+      result = findDocComment(n[1])
   elif n.kind in {nkAsgn, nkFastAsgn} and n.len == 2:
-    result = findDocComment(n.sons[1])
+    result = findDocComment(n[1])
 
 proc extractDocComment(s: PSym): string =
   var n = findDocComment(s.ast)
@@ -256,7 +256,7 @@ proc suggestField(c: PContext, s: PSym; f: PNode; info: TLineInfo; outputs: var
 
 proc getQuality(s: PSym): range[0..100] =
   if s.typ != nil and s.typ.len > 1:
-    var exp = s.typ.sons[1].skipTypes({tyGenericInst, tyVar, tyLent, tyAlias, tySink})
+    var exp = s.typ[1].skipTypes({tyGenericInst, tyVar, tyLent, tyAlias, tySink})
     if exp.kind == tyVarargs: exp = elemType(exp)
     if exp.kind in {tyUntyped, tyTyped, tyGenericParam, tyAnything}: return 50
   return 100
@@ -275,26 +275,25 @@ template wholeSymTab(cond, section: untyped) {.dirty.} =
                                  pm, c.inTypeContext > 0, scopeN))
 
 proc suggestSymList(c: PContext, list, f: PNode; info: TLineInfo, outputs: var Suggestions) =
-  for i in 0 ..< len(list):
-    if list.sons[i].kind == nkSym:
-      suggestField(c, list.sons[i].sym, f, info, outputs)
+  for i in 0..<list.len:
+    if list[i].kind == nkSym:
+      suggestField(c, list[i].sym, f, info, outputs)
     #else: InternalError(list.info, "getSymFromList")
 
 proc suggestObject(c: PContext, n, f: PNode; info: TLineInfo, outputs: var Suggestions) =
   case n.kind
   of nkRecList:
-    for i in 0 ..< len(n): suggestObject(c, n.sons[i], f, info, outputs)
+    for i in 0..<n.len: suggestObject(c, n[i], f, info, outputs)
   of nkRecCase:
-    var L = len(n)
-    if L > 0:
-      suggestObject(c, n.sons[0], f, info, outputs)
-      for i in 1 ..< L: suggestObject(c, lastSon(n.sons[i]), f, info, outputs)
+    if n.len > 0:
+      suggestObject(c, n[0], f, info, outputs)
+      for i in 1..<n.len: suggestObject(c, lastSon(n[i]), f, info, outputs)
   of nkSym: suggestField(c, n.sym, f, info, outputs)
   else: discard
 
 proc nameFits(c: PContext, s: PSym, n: PNode): bool =
-  var op = if n.kind in nkCallKinds: n.sons[0] else: n
-  if op.kind in {nkOpenSymChoice, nkClosedSymChoice}: op = op.sons[0]
+  var op = if n.kind in nkCallKinds: n[0] else: n
+  if op.kind in {nkOpenSymChoice, nkClosedSymChoice}: op = op[0]
   var opr: PIdent
   case op.kind
   of nkSym: opr = op.sym.name
@@ -305,8 +304,7 @@ proc nameFits(c: PContext, s: PSym, n: PNode): bool =
 proc argsFit(c: PContext, candidate: PSym, n, nOrig: PNode): bool =
   case candidate.kind
   of OverloadableSyms:
-    var m: TCandidate
-    initCandidate(c, m, candidate, nil)
+    var m = newCandidate(c, candidate, nil)
     sigmatch.partialMatch(c, n, nOrig, m)
     result = m.state != csNoMatch
   else:
@@ -322,17 +320,17 @@ proc suggestVar(c: PContext, n: PNode, outputs: var Suggestions) =
   wholeSymTab(nameFits(c, it, n), ideCon)
 
 proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} =
-  if s.typ != nil and len(s.typ) > 1 and s.typ.sons[1] != nil:
+  if s.typ != nil and s.typ.len > 1 and s.typ[1] != nil:
     # special rule: if system and some weird generic match via 'tyUntyped'
     # or 'tyGenericParam' we won't list it either to reduce the noise (nobody
     # wants 'system.`-|` as suggestion
     let m = s.getModule()
     if m != nil and sfSystemModule in m.flags:
       if s.kind == skType: return
-      var exp = s.typ.sons[1].skipTypes({tyGenericInst, tyVar, tyLent, tyAlias, tySink})
+      var exp = s.typ[1].skipTypes({tyGenericInst, tyVar, tyLent, tyAlias, tySink})
       if exp.kind == tyVarargs: exp = elemType(exp)
       if exp.kind in {tyUntyped, tyTyped, tyGenericParam, tyAnything}: return
-    result = sigmatch.argtypeMatches(c, s.typ.sons[1], firstArg)
+    result = sigmatch.argtypeMatches(c, s.typ[1], firstArg)
 
 proc suggestOperations(c: PContext, n, f: PNode, typ: PType, outputs: var Suggestions) =
   assert typ != nil
@@ -395,7 +393,7 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions)
     var t = typ
     while t != nil:
       suggestSymList(c, t.n, field, n.info, outputs)
-      t = t.sons[0]
+      t = t[0]
     suggestOperations(c, n, field, typ, outputs)
   else:
     let orig = typ # skipTypes(typ, {tyGenericInst, tyAlias, tySink})
@@ -404,8 +402,8 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions)
       var t = typ
       while true:
         suggestObject(c, t.n, field, n.info, outputs)
-        if t.sons[0] == nil: break
-        t = skipTypes(t.sons[0], skipPtrs)
+        if t[0] == nil: break
+        t = skipTypes(t[0], skipPtrs)
     elif typ.kind == tyTuple and typ.n != nil:
       suggestSymList(c, typ.n, field, n.info, outputs)
     suggestOperations(c, n, field, orig, outputs)
@@ -456,7 +454,7 @@ proc findUsages(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym) =
 
 when defined(nimsuggest):
   proc listUsages*(conf: ConfigRef; s: PSym) =
-    #echo "usages ", len(s.allUsages)
+    #echo "usages ", s.allUsages.len
     for info in s.allUsages:
       let x = if info == s.info and info.col == s.info.col: ideDef else: ideUse
       suggestResult(conf, symToSuggest(conf, s, isLocal=false, x, info, 100, PrefixMatch.None, false, 0))
@@ -571,7 +569,7 @@ proc safeSemExpr*(c: PContext, n: PNode): PNode =
 
 proc sugExpr(c: PContext, n: PNode, outputs: var Suggestions) =
   if n.kind == nkDotExpr:
-    var obj = safeSemExpr(c, n.sons[0])
+    var obj = safeSemExpr(c, n[0])
     # it can happen that errnously we have collected the fieldname
     # of the next line, so we check the 'field' is actually on the same
     # line as the object to prevent this from happening:
@@ -596,14 +594,14 @@ proc suggestExprNoCheck*(c: PContext, n: PNode) =
   elif c.config.ideCmd == ideCon:
     if n.kind in nkCallKinds:
       var a = copyNode(n)
-      var x = safeSemExpr(c, n.sons[0])
-      if x.kind == nkEmpty or x.typ == nil: x = n.sons[0]
-      addSon(a, x)
-      for i in 1..len(n)-1:
+      var x = safeSemExpr(c, n[0])
+      if x.kind == nkEmpty or x.typ == nil: x = n[0]
+      a.add x
+      for i in 1..<n.len:
         # use as many typed arguments as possible:
-        var x = safeSemExpr(c, n.sons[i])
+        var x = safeSemExpr(c, n[i])
         if x.kind == nkEmpty or x.typ == nil: break
-        addSon(a, x)
+        a.add x
       suggestCall(c, a, n, outputs)
     elif n.kind in nkIdentKinds:
       var x = safeSemExpr(c, n)
diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim
index 3b67b3263..59016b2b6 100644
--- a/compiler/syntaxes.nim
+++ b/compiler/syntaxes.nim
@@ -85,20 +85,20 @@ proc parsePipe(filename: AbsoluteFile, inputStream: PLLStream; cache: IdentCache
     llStreamClose(s)
 
 proc getFilter(ident: PIdent): TFilterKind =
-  for i in low(TFilterKind) .. high(TFilterKind):
+  for i in low(TFilterKind)..high(TFilterKind):
     if cmpIgnoreStyle(ident.s, filterNames[i]) == 0:
       return i
   result = filtNone
 
 proc getParser(conf: ConfigRef; n: PNode; ident: PIdent): TParserKind =
-  for i in low(TParserKind) .. high(TParserKind):
+  for i in low(TParserKind)..high(TParserKind):
     if cmpIgnoreStyle(ident.s, parserNames[i]) == 0:
       return i
   localError(conf, n.info, "unknown parser: " & ident.s)
 
 proc getCallee(conf: ConfigRef; n: PNode): PIdent =
-  if n.kind in nkCallKinds and n.sons[0].kind == nkIdent:
-    result = n.sons[0].ident
+  if n.kind in nkCallKinds and n[0].kind == nkIdent:
+    result = n[0].ident
   elif n.kind == nkIdent:
     result = n.ident
   else:
@@ -131,13 +131,13 @@ proc evalPipe(p: var TParsers, n: PNode, filename: AbsoluteFile,
   result = start
   if n.kind == nkEmpty: return
   if n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "|":
-    for i in 1 .. 2:
-      if n.sons[i].kind == nkInfix:
-        result = evalPipe(p, n.sons[i], filename, result)
+    for i in 1..2:
+      if n[i].kind == nkInfix:
+        result = evalPipe(p, n[i], filename, result)
       else:
-        result = applyFilter(p, n.sons[i], filename, result)
+        result = applyFilter(p, n[i], filename, result)
   elif n.kind == nkStmtList:
-    result = evalPipe(p, n.sons[0], filename, result)
+    result = evalPipe(p, n[0], filename, result)
   else:
     result = applyFilter(p, n, filename, result)
 
@@ -168,7 +168,7 @@ proc setupParsers*(p: var TParsers; fileIdx: FileIndex; cache: IdentCache;
   openParsers(p, fileIdx, llStreamOpen(f), cache, config)
   result = true
 
-proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode {.procvar.} =
+proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode =
   var p: TParsers
   if setupParsers(p, fileIdx, cache, config):
     result = parseAll(p)
diff --git a/compiler/tccgen.nim b/compiler/tccgen.nim
index 2301ad404..8397185e8 100644
--- a/compiler/tccgen.nim
+++ b/compiler/tccgen.nim
@@ -70,7 +70,7 @@ proc compileCCode*(ccode: string) =
 
 proc run*(args: string) =
   var s = @[cstring(gProjectName)] & map(split(args), proc(x: string): cstring = cstring(x))
-  var err = tinyc.run(gTinyC, cint(len(s)), cast[cstringArray](addr(s[0]))) != 0'i32
+  var err = tinyc.run(gTinyC, cint(s.len), cast[cstringArray](addr(s[0]))) != 0'i32
   closeCCState(gTinyC)
   if err: rawMessage(errExecutionOfProgramFailed, "")
 
diff --git a/compiler/transf.nim b/compiler/transf.nim
index c998b53b5..68ef464c4 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -29,14 +29,12 @@ proc transformBody*(g: ModuleGraph, prc: PSym, cache: bool): PNode
 import closureiters, lambdalifting
 
 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
+    forLoopBody: PNode   # 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
@@ -52,39 +50,22 @@ type
     graph: ModuleGraph
   PTransf = ref TTransfContext
 
-proc newTransNode(a: PNode): PTransNode {.inline.} =
-  result = PTransNode(shallowCopy(a))
+proc newTransNode(a: PNode): PNode {.inline.} =
+  result = shallowCopy(a)
 
 proc newTransNode(kind: TNodeKind, info: TLineInfo,
-                  sons: int): PTransNode {.inline.} =
+                  sons: int): PNode {.inline.} =
   var x = newNodeI(kind, info)
   newSeq(x.sons, sons)
-  result = x.PTransNode
+  result = x
 
 proc newTransNode(kind: TNodeKind, n: PNode,
-                  sons: int): PTransNode {.inline.} =
+                  sons: int): PNode {.inline.} =
   var x = newNodeIT(kind, n.info, n.typ)
   newSeq(x.sons, sons)
   x.typ = n.typ
 #  x.flags = n.flags
-  result = x.PTransNode
-
-proc add(a, b: PTransNode) {.inline.} = addSon(PNode(a), PNode(b))
-proc len(a: PTransNode): int {.inline.} = len(a.PNode)
-
-proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} =
-  var n = PNode(a)
-  n.sons[i] = PNode(x)
-
-proc `[]=`(a: PTransNode, i: BackwardsIndex, x: PTransNode) {.inline.} =
-  `[]=`(a, a.len - i.int, x)
-
-proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} =
-  var n = PNode(a)
-  result = n.sons[i].PTransNode
-
-proc `[]`(a: PTransNode, i: BackwardsIndex): PTransNode {.inline.} =
-  `[]`(a, a.len - i.int)
+  result = x
 
 proc newTransCon(owner: PSym): PTransCon =
   assert owner != nil
@@ -114,16 +95,16 @@ proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode =
   else:
     result = newSymNode(r)
 
-proc transform(c: PTransf, n: PNode): PTransNode
+proc transform(c: PTransf, n: PNode): PNode
 
-proc transformSons(c: PTransf, n: PNode): PTransNode =
+proc transformSons(c: PTransf, n: PNode): PNode =
   result = newTransNode(n)
-  for i in 0 ..< len(n):
-    result[i] = transform(c, n.sons[i])
+  for i in 0..<n.len:
+    result[i] = transform(c, n[i])
 
-proc newAsgnStmt(c: PTransf, kind: TNodeKind, le: PNode, ri: PTransNode): PTransNode =
-  result = newTransNode(kind, PNode(ri).info, 2)
-  result[0] = PTransNode(le)
+proc newAsgnStmt(c: PTransf, kind: TNodeKind, le: PNode, ri: PNode): PNode =
+  result = newTransNode(kind, ri.info, 2)
+  result[0] = le
   result[1] = ri
 
 proc transformSymAux(c: PTransf, n: PNode): PNode =
@@ -160,8 +141,8 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
     tc = tc.next
   result = b
 
-proc transformSym(c: PTransf, n: PNode): PTransNode =
-  result = PTransNode(transformSymAux(c, n))
+proc transformSym(c: PTransf, n: PNode): PNode =
+  result = transformSymAux(c, n)
 
 proc freshVar(c: PTransf; v: PSym): PNode =
   let owner = getCurrOwner(c)
@@ -173,25 +154,25 @@ proc freshVar(c: PTransf; v: PSym): PNode =
     newVar.owner = owner
     result = newSymNode(newVar)
 
-proc transformVarSection(c: PTransf, v: PNode): PTransNode =
+proc transformVarSection(c: PTransf, v: PNode): PNode =
   result = newTransNode(v)
-  for i in 0 ..< len(v):
-    var it = v.sons[i]
+  for i in 0..<v.len:
+    var it = v[i]
     if it.kind == nkCommentStmt:
-      result[i] = PTransNode(it)
+      result[i] = it
     elif it.kind == nkIdentDefs:
-      if it.sons[0].kind == nkSym:
+      if it[0].kind == nkSym:
         internalAssert(c.graph.config, it.len == 3)
-        let x = freshVar(c, it.sons[0].sym)
-        idNodeTablePut(c.transCon.mapping, it.sons[0].sym, x)
+        let x = freshVar(c, it[0].sym)
+        idNodeTablePut(c.transCon.mapping, it[0].sym, x)
         var defs = newTransNode(nkIdentDefs, it.info, 3)
         if importantComments(c.graph.config):
           # keep documentation information:
-          PNode(defs).comment = it.comment
-        defs[0] = x.PTransNode
-        defs[1] = it.sons[1].PTransNode
-        defs[2] = transform(c, it.sons[2])
-        if x.kind == nkSym: x.sym.ast = defs[2].PNode
+          defs.comment = it.comment
+        defs[0] = x
+        defs[1] = it[1]
+        defs[2] = transform(c, it[2])
+        if x.kind == nkSym: x.sym.ast = defs[2]
         result[i] = defs
       else:
         # has been transformed into 'param.x' for closure iterators, so just
@@ -200,65 +181,64 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode =
     else:
       if it.kind != nkVarTuple:
         internalError(c.graph.config, it.info, "transformVarSection: not nkVarTuple")
-      var L = len(it)
-      var defs = newTransNode(it.kind, it.info, L)
-      for j in 0 .. L-3:
+      var defs = newTransNode(it.kind, it.info, it.len)
+      for j in 0..<it.len-2:
         if it[j].kind == nkSym:
-          let x = freshVar(c, it.sons[j].sym)
-          idNodeTablePut(c.transCon.mapping, it.sons[j].sym, x)
-          defs[j] = x.PTransNode
+          let x = freshVar(c, it[j].sym)
+          idNodeTablePut(c.transCon.mapping, it[j].sym, x)
+          defs[j] = x
         else:
           defs[j] = transform(c, it[j])
-      assert(it.sons[L-2].kind == nkEmpty)
-      defs[L-2] = newNodeI(nkEmpty, it.info).PTransNode
-      defs[L-1] = transform(c, it.sons[L-1])
+      assert(it[^2].kind == nkEmpty)
+      defs[^2] = newNodeI(nkEmpty, it.info)
+      defs[^1] = transform(c, it[^1])
       result[i] = defs
 
-proc transformConstSection(c: PTransf, v: PNode): PTransNode =
-  result = PTransNode(v)
+proc transformConstSection(c: PTransf, v: PNode): PNode =
+  result = v
   when false:
     result = newTransNode(v)
-    for i in 0 ..< len(v):
-      var it = v.sons[i]
+    for i in 0..<v.len:
+      var it = v[i]
       if it.kind == nkCommentStmt:
-        result[i] = PTransNode(it)
+        result[i] = it
       else:
         if it.kind != nkConstDef: internalError(c.graph.config, it.info, "transformConstSection")
-        if it.sons[0].kind != nkSym:
-          debug it.sons[0]
+        if it[0].kind != nkSym:
+          debug it[0]
           internalError(c.graph.config, it.info, "transformConstSection")
 
-        result[i] = PTransNode(it)
+        result[i] = it
 
 proc hasContinue(n: PNode): bool =
   case n.kind
   of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: discard
   of nkContinueStmt: result = true
   else:
-    for i in 0 ..< len(n):
-      if hasContinue(n.sons[i]): return true
+    for i in 0..<n.len:
+      if hasContinue(n[i]): return true
 
 proc newLabel(c: PTransf, n: PNode): PSym =
   result = newSym(skLabel, nil, getCurrOwner(c), n.info)
   result.name = getIdent(c.graph.cache, genPrefix & $result.id)
 
-proc transformBlock(c: PTransf, n: PNode): PTransNode =
+proc transformBlock(c: PTransf, n: PNode): PNode =
   var labl: PSym
   if c.inlining > 0:
     labl = newLabel(c, n[0])
     idNodeTablePut(c.transCon.mapping, n[0].sym, newSymNode(labl))
   else:
     labl =
-      if n.sons[0].kind != nkEmpty:
-        n.sons[0].sym  # already named block? -> Push symbol on the stack
+      if n[0].kind != nkEmpty:
+        n[0].sym  # already named block? -> Push symbol on the stack
       else:
         newLabel(c, n)
   c.breakSyms.add(labl)
   result = transformSons(c, n)
   discard c.breakSyms.pop
-  result[0] = newSymNode(labl).PTransNode
+  result[0] = newSymNode(labl)
 
-proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
+proc transformLoopBody(c: PTransf, n: PNode): PNode =
   # What if it contains "continue" and "break"? "break" needs
   # an explicit label too, but not the same!
 
@@ -270,41 +250,41 @@ proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
     c.contSyms.add(labl)
 
     result = newTransNode(nkBlockStmt, n.info, 2)
-    result[0] = newSymNode(labl).PTransNode
+    result[0] = newSymNode(labl)
     result[1] = transform(c, n)
     discard c.contSyms.pop()
   else:
     result = transform(c, n)
 
-proc transformWhile(c: PTransf; n: PNode): PTransNode =
+proc transformWhile(c: PTransf; n: PNode): PNode =
   if c.inlining > 0:
     result = transformSons(c, n)
   else:
     let labl = newLabel(c, n)
     c.breakSyms.add(labl)
     result = newTransNode(nkBlockStmt, n.info, 2)
-    result[0] = newSymNode(labl).PTransNode
+    result[0] = newSymNode(labl)
 
     var body = newTransNode(n)
-    for i in 0..n.len-2:
-      body[i] = transform(c, n.sons[i])
-    body[n.len-1] = transformLoopBody(c, n.sons[n.len-1])
+    for i in 0..<n.len-1:
+      body[i] = transform(c, n[i])
+    body[^1] = transformLoopBody(c, n[^1])
     result[1] = body
     discard c.breakSyms.pop
 
-proc transformBreak(c: PTransf, n: PNode): PTransNode =
+proc transformBreak(c: PTransf, n: PNode): PNode =
   result = transformSons(c, n)
-  if n.sons[0].kind == nkEmpty and c.breakSyms.len > 0:
+  if n[0].kind == nkEmpty and c.breakSyms.len > 0:
     let labl = c.breakSyms[c.breakSyms.high]
-    result[0] = newSymNode(labl).PTransNode
+    result[0] = newSymNode(labl)
 
-proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
+proc introduceNewLocalVars(c: PTransf, n: PNode): PNode =
   case n.kind
   of nkSym:
     result = transformSym(c, n)
   of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
     # nothing to be done for leaves:
-    result = PTransNode(n)
+    result = n
   of nkVarSection, nkLetSection:
     result = transformVarSection(c, n)
   of nkClosure:
@@ -313,14 +293,14 @@ proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
     # (bug #2604). We need to patch this environment here too:
     let a = n[1]
     if a.kind == nkSym:
-      n.sons[1] = transformSymAux(c, a)
-    return PTransNode(n)
+      n[1] = transformSymAux(c, a)
+    return n
   else:
     result = newTransNode(n)
-    for i in 0 ..< len(n):
-      result[i] = introduceNewLocalVars(c, n.sons[i])
+    for i in 0..<n.len:
+      result[i] = introduceNewLocalVars(c, n[i])
 
-proc transformAsgn(c: PTransf, n: PNode): PTransNode =
+proc transformAsgn(c: PTransf, n: PNode): PNode =
   let rhs = n[1]
 
   if rhs.kind != nkTupleConstr:
@@ -334,15 +314,15 @@ proc transformAsgn(c: PTransf, n: PNode): PTransNode =
   for i, field in rhs:
     let val = if field.kind == nkExprColonExpr: field[1] else: field
     let def = newTransNode(nkIdentDefs, field.info, 3)
-    def[0] = PTransNode(newTemp(c, val.typ, field.info))
-    def[1] = PTransNode(newNodeI(nkEmpty, field.info))
+    def[0] = newTemp(c, val.typ, field.info)
+    def[1] = newNodeI(nkEmpty, field.info)
     def[2] = transform(c, val)
     letSection[i] = def
     # NOTE: We assume the constructor fields are in the correct order for the
     # given tuple type
     newTupleConstr[i] = def[0]
 
-  PNode(newTupleConstr).typ = rhs.typ
+  newTupleConstr.typ = rhs.typ
 
   let asgnNode = newTransNode(nkAsgn, n.info, 2)
   asgnNode[0] = transform(c, n[0])
@@ -352,8 +332,8 @@ proc transformAsgn(c: PTransf, n: PNode): PTransNode =
   result[0] = letSection
   result[1] = asgnNode
 
-proc transformYield(c: PTransf, n: PNode): PTransNode =
-  proc asgnTo(lhs: PNode, rhs: PTransNode): PTransNode =
+proc transformYield(c: PTransf, n: PNode): PNode =
+  proc asgnTo(lhs: PNode, rhs: PNode): PNode =
     # Choose the right assignment instruction according to the given ``lhs``
     # node since it may not be a nkSym (a stack-allocated skForVar) but a
     # nkDotExpr (a heap-allocated slot into the envP block)
@@ -366,87 +346,87 @@ proc transformYield(c: PTransf, n: PNode): PTransNode =
     else:
       internalAssert c.graph.config, false
   result = newTransNode(nkStmtList, n.info, 0)
-  var e = n.sons[0]
+  var e = n[0]
   # c.transCon.forStmt.len == 3 means that there is one for loop variable
   # and thus no tuple unpacking:
   if e.typ.isNil: return result # can happen in nimsuggest for unknown reasons
   if c.transCon.forStmt.len != 3:
     e = skipConv(e)
     if e.kind in {nkPar, nkTupleConstr}:
-      for i in 0 ..< len(e):
-        var v = e.sons[i]
-        if v.kind == nkExprColonExpr: v = v.sons[1]
+      for i in 0..<e.len:
+        var v = e[i]
+        if v.kind == nkExprColonExpr: v = v[1]
         if c.transCon.forStmt[i].kind == nkVarTuple:
-          for j in 0 ..< len(c.transCon.forStmt[i])-1:
+          for j in 0..<c.transCon.forStmt[i].len-1:
             let lhs = c.transCon.forStmt[i][j]
             let rhs = transform(c, newTupleAccess(c.graph, v, j))
-            add(result, asgnTo(lhs, rhs))
+            result.add(asgnTo(lhs, rhs))
         else:
-          let lhs = c.transCon.forStmt.sons[i]
+          let lhs = c.transCon.forStmt[i]
           let rhs = transform(c, v)
-          add(result, asgnTo(lhs, rhs))
+          result.add(asgnTo(lhs, rhs))
     else:
       # Unpack the tuple into the loop variables
       # XXX: BUG: what if `n` is an expression with side-effects?
-      for i in 0 .. len(c.transCon.forStmt) - 3:
-        let lhs = c.transCon.forStmt.sons[i]
+      for i in 0..<c.transCon.forStmt.len - 2:
+        let lhs = c.transCon.forStmt[i]
         let rhs = transform(c, newTupleAccess(c.graph, e, i))
-        add(result, asgnTo(lhs, rhs))
+        result.add(asgnTo(lhs, rhs))
   else:
-    if c.transCon.forStmt.sons[0].kind == nkVarTuple:
-      for i in 0 ..< len(c.transCon.forStmt[0])-1:
+    if c.transCon.forStmt[0].kind == nkVarTuple:
+      for i in 0..<c.transCon.forStmt[0].len-1:
         let lhs = c.transCon.forStmt[0][i]
         let rhs = transform(c, newTupleAccess(c.graph, e, i))
-        add(result, asgnTo(lhs, rhs))
+        result.add(asgnTo(lhs, rhs))
     else:
-      let lhs = c.transCon.forStmt.sons[0]
+      let lhs = c.transCon.forStmt[0]
       let rhs = transform(c, e)
-      add(result, asgnTo(lhs, rhs))
+      result.add(asgnTo(lhs, rhs))
 
   inc(c.transCon.yieldStmts)
   if c.transCon.yieldStmts <= 1:
     # common case
-    add(result, c.transCon.forLoopBody)
+    result.add(c.transCon.forLoopBody)
   else:
     # we need to introduce new local variables:
-    add(result, introduceNewLocalVars(c, c.transCon.forLoopBody.PNode))
+    result.add(introduceNewLocalVars(c, c.transCon.forLoopBody))
   if result.len > 0:
-    var changeNode = PNode(result[0])
+    var changeNode = result[0]
     changeNode.info = c.transCon.forStmt.info
     for i, child in changeNode:
       child.info = changeNode.info
 
-proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
+proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PNode =
   result = transformSons(c, n)
   if c.graph.config.cmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return
-  var n = result.PNode
-  case n.sons[0].kind
+  var n = result
+  case n[0].kind
   of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
-    var m = n.sons[0].sons[0]
+    var m = n[0][0]
     if m.kind == a or m.kind == b:
       # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
-      n.sons[0].sons[0] = m.sons[0]
-      result = PTransNode(n.sons[0])
+      n[0][0] = m[0]
+      result = n[0]
       if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
-        PNode(result).typ = n.typ
+        result.typ = n.typ
       elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
-        PNode(result).typ = toVar(PNode(result).typ)
+        result.typ = toVar(result.typ)
   of nkHiddenStdConv, nkHiddenSubConv, nkConv:
-    var m = n.sons[0].sons[1]
+    var m = n[0][1]
     if m.kind == a or m.kind == b:
       # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
-      n.sons[0].sons[1] = m.sons[0]
-      result = PTransNode(n.sons[0])
+      n[0][1] = m[0]
+      result = n[0]
       if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
-        PNode(result).typ = n.typ
+        result.typ = n.typ
       elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
-        PNode(result).typ = toVar(PNode(result).typ)
+        result.typ = toVar(result.typ)
   else:
-    if n.sons[0].kind == a or n.sons[0].kind == b:
+    if n[0].kind == a or n[0].kind == b:
       # addr ( deref ( x )) --> x
-      result = PTransNode(n.sons[0].sons[0])
+      result = n[0][0]
       if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
-        PNode(result).typ = n.typ
+        result.typ = n.typ
 
 proc generateThunk(c: PTransf; prc: PNode, dest: PType): PNode =
   ## Converts 'prc' into '(thunk, nil)' so that it's compatible with
@@ -464,18 +444,18 @@ proc generateThunk(c: PTransf; prc: PNode, dest: PType): PNode =
   result.add(conv)
   result.add(newNodeIT(nkNilLit, prc.info, getSysType(c.graph, prc.info, tyNil)))
 
-proc transformConv(c: PTransf, n: PNode): PTransNode =
+proc transformConv(c: PTransf, n: PNode): PNode =
   # numeric types need range checks:
   var dest = skipTypes(n.typ, abstractVarRange)
-  var source = skipTypes(n.sons[1].typ, abstractVarRange)
+  var source = skipTypes(n[1].typ, abstractVarRange)
   case dest.kind
   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(c.graph.config, n.typ) <= firstOrd(c.graph.config, n.sons[1].typ) and
-        lastOrd(c.graph.config, n.sons[1].typ) <= lastOrd(c.graph.config, n.typ):
+    elif firstOrd(c.graph.config, n.typ) <= firstOrd(c.graph.config, n[1].typ) and
+        lastOrd(c.graph.config, n[1].typ) <= lastOrd(c.graph.config, n.typ):
       # BUGFIX: simply leave n as it is; we need a nkConv node,
       # but no range check:
       result = transformSons(c, n)
@@ -486,34 +466,34 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
       else:
         result = newTransNode(nkChckRange, n, 3)
       dest = skipTypes(n.typ, abstractVar)
-      result[0] = transform(c, n.sons[1])
-      result[1] = newIntTypeNode(firstOrd(c.graph.config, dest), dest).PTransNode
-      result[2] = newIntTypeNode(lastOrd(c.graph.config, dest), dest).PTransNode
+      result[0] = transform(c, n[1])
+      result[1] = newIntTypeNode(firstOrd(c.graph.config, dest), dest)
+      result[2] = newIntTypeNode(lastOrd(c.graph.config, dest), dest)
   of tyFloat..tyFloat128:
     # XXX int64 -> float conversion?
     if skipTypes(n.typ, abstractVar).kind == tyRange:
       result = newTransNode(nkChckRangeF, n, 3)
       dest = skipTypes(n.typ, abstractVar)
-      result[0] = transform(c, n.sons[1])
-      result[1] = copyTree(dest.n.sons[0]).PTransNode
-      result[2] = copyTree(dest.n.sons[1]).PTransNode
+      result[0] = transform(c, n[1])
+      result[1] = copyTree(dest.n[0])
+      result[2] = copyTree(dest.n[1])
     else:
       result = transformSons(c, n)
   of tyOpenArray, tyVarargs:
-    result = transform(c, n.sons[1])
-    PNode(result).typ = takeType(n.typ, n.sons[1].typ)
-    #echo n.info, " came here and produced ", typeToString(PNode(result).typ),
-    #   " from ", typeToString(n.typ), " and ", typeToString(n.sons[1].typ)
+    result = transform(c, n[1])
+    result.typ = takeType(n.typ, n[1].typ)
+    #echo n.info, " came here and produced ", typeToString(result.typ),
+    #   " from ", typeToString(n.typ), " and ", typeToString(n[1].typ)
   of tyCString:
     if source.kind == tyString:
       result = newTransNode(nkStringToCString, n, 1)
-      result[0] = transform(c, n.sons[1])
+      result[0] = transform(c, n[1])
     else:
       result = transformSons(c, n)
   of tyString:
     if source.kind == tyCString:
       result = newTransNode(nkCStringToString, n, 1)
-      result[0] = transform(c, n.sons[1])
+      result[0] = transform(c, n[1])
     else:
       result = transformSons(c, n)
   of tyRef, tyPtr:
@@ -523,31 +503,31 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
       var diff = inheritanceDiff(dest, source)
       if diff < 0:
         result = newTransNode(nkObjUpConv, n, 1)
-        result[0] = transform(c, n.sons[1])
+        result[0] = transform(c, n[1])
       elif diff > 0 and diff != high(int):
         result = newTransNode(nkObjDownConv, n, 1)
-        result[0] = transform(c, n.sons[1])
+        result[0] = transform(c, n[1])
       else:
-        result = transform(c, n.sons[1])
+        result = transform(c, n[1])
     else:
       result = transformSons(c, n)
   of tyObject:
     var diff = inheritanceDiff(dest, source)
     if diff < 0:
       result = newTransNode(nkObjUpConv, n, 1)
-      result[0] = transform(c, n.sons[1])
+      result[0] = transform(c, n[1])
     elif diff > 0 and diff != high(int):
       result = newTransNode(nkObjDownConv, n, 1)
-      result[0] = transform(c, n.sons[1])
+      result[0] = transform(c, n[1])
     else:
-      result = transform(c, n.sons[1])
+      result = transform(c, n[1])
   of tyGenericParam, tyOrdinal:
-    result = transform(c, n.sons[1])
+    result = transform(c, n[1])
     # happens sometimes for generated assignments, etc.
   of tyProc:
     result = transformSons(c, n)
     if dest.callConv == ccClosure and source.callConv == ccDefault:
-      result = generateThunk(c, result[1].PNode, dest).PTransNode
+      result = generateThunk(c, result[1], dest)
   else:
     result = transformSons(c, n)
 
@@ -574,8 +554,8 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
     result = paDirectMapping
   of nkPar, nkTupleConstr, nkCurly, nkBracket:
     result = paFastAsgn
-    for i in 0 ..< len(arg):
-      if putArgInto(arg.sons[i], formal) != paDirectMapping: return
+    for i in 0..<arg.len:
+      if putArgInto(arg[i], formal) != paDirectMapping: return
     result = paDirectMapping
   else:
     if skipTypes(formal, abstractInst).kind in {tyVar, tyLent}: result = paVarAsgn
@@ -583,35 +563,34 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
 
 proc findWrongOwners(c: PTransf, n: PNode) =
   if n.kind == nkVarSection:
-    let x = n.sons[0].sons[0]
+    let x = n[0][0]
     if x.kind == nkSym and x.sym.owner != getCurrOwner(c):
       internalError(c.graph.config, 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])
+    for i in 0..<n.safeLen: findWrongOwners(c, n[i])
 
-proc transformFor(c: PTransf, n: PNode): PTransNode =
+proc transformFor(c: PTransf, n: PNode): PNode =
   # generate access statements for the parameters (unless they are constant)
   # put mapping from formal parameters to actual parameters
   if n.kind != nkForStmt: internalError(c.graph.config, n.info, "transformFor")
 
-  var length = len(n)
-  var call = n.sons[length - 2]
+  var call = n[^2]
 
   let labl = newLabel(c, n)
   result = newTransNode(nkBlockStmt, n.info, 2)
-  result[0] = newSymNode(labl).PTransNode
+  result[0] = newSymNode(labl)
   if call.typ.isNil:
     # see bug #3051
-    result[1] = newNode(nkEmpty).PTransNode
+    result[1] = newNode(nkEmpty)
     return result
   c.breakSyms.add(labl)
-  if call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
-      call.sons[0].typ.skipTypes(abstractInst).callConv == ccClosure:
-    result[1] = n.PTransNode
+  if call.kind notin nkCallKinds or call[0].kind != nkSym or
+      call[0].typ.skipTypes(abstractInst).callConv == ccClosure:
+    result[1] = n
     result[1][^1] = transformLoopBody(c, n[^1])
     result[1][^2] = transform(c, n[^2])
-    result[1] = lambdalifting.liftForLoop(c.graph, result[1].PNode, getCurrOwner(c)).PTransNode
+    result[1] = lambdalifting.liftForLoop(c.graph, result[1], getCurrOwner(c))
     discard c.breakSyms.pop
     return result
 
@@ -619,22 +598,22 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
   var stmtList = newTransNode(nkStmtList, n.info, 0)
   result[1] = stmtList
 
-  var loopBody = transformLoopBody(c, n.sons[length-1])
+  var loopBody = transformLoopBody(c, n[^1])
 
   discard c.breakSyms.pop
 
   var v = newNodeI(nkVarSection, n.info)
-  for i in 0 .. length - 3:
+  for i in 0..<n.len - 2:
     if n[i].kind == nkVarTuple:
-      for j in 0 ..< len(n[i])-1:
+      for j in 0..<n[i].len-1:
         addVar(v, copyTree(n[i][j])) # declare new vars
     else:
-      addVar(v, copyTree(n.sons[i])) # declare new vars
-  add(stmtList, v.PTransNode)
+      addVar(v, copyTree(n[i])) # declare new vars
+  stmtList.add(v)
 
   # Bugfix: inlined locals belong to the invoking routine, not to the invoked
   # iterator!
-  let iter = call.sons[0].sym
+  let iter = call[0].sym
   var newC = newTransCon(getCurrOwner(c))
   newC.forStmt = n
   newC.forLoopBody = loopBody
@@ -642,12 +621,12 @@ 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 1 ..< len(call):
-    var arg = transform(c, call.sons[i]).PNode
+  for i in 1..<call.len:
+    var arg = transform(c, call[i])
     let ff = skipTypes(iter.typ, abstractInst)
     # can happen for 'nim check':
     if i >= ff.n.len: return result
-    var formal = ff.n.sons[i].sym
+    var formal = ff.n[i].sym
     let pa = putArgInto(arg, formal.typ)
     case pa
     of paDirectMapping:
@@ -663,7 +642,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
       # generate a temporary and produce an assignment statement:
       var temp = newTemp(c, t, formal.info)
       addVar(v, temp)
-      add(stmtList, newAsgnStmt(c, nkFastAsgn, temp, arg.PTransNode))
+      stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, arg))
       idNodeTablePut(newC.mapping, formal, temp)
     of paVarAsgn:
       assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
@@ -671,150 +650,149 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
       # XXX BUG still not correct if the arg has a side effect!
     of paComplexOpenarray:
       let typ = newType(tySequence, formal.owner)
-      addSonSkipIntLit(typ, formal.typ.sons[0])
+      addSonSkipIntLit(typ, formal.typ[0])
       var temp = newTemp(c, typ, formal.info)
       addVar(v, temp)
-      add(stmtList, newAsgnStmt(c, nkFastAsgn, temp, arg.PTransNode))
+      stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, arg))
       idNodeTablePut(newC.mapping, formal, temp)
 
   let body = transformBody(c.graph, iter, true)
   pushInfoContext(c.graph.config, n.info)
   inc(c.inlining)
-  add(stmtList, transform(c, body))
+  stmtList.add(transform(c, body))
   #findWrongOwners(c, stmtList.pnode)
   dec(c.inlining)
   popInfoContext(c.graph.config)
   popTransCon(c)
-  # echo "transformed: ", stmtList.PNode.renderTree
+  # echo "transformed: ", stmtList.renderTree
 
-proc transformCase(c: PTransf, n: PNode): PTransNode =
+proc transformCase(c: PTransf, n: PNode): PNode =
   # 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 .. len(n)-1:
-    var it = n.sons[i]
+  var ifs: PNode = nil
+  for it in n:
     var e = transform(c, it)
     case it.kind
     of nkElifBranch:
-      if ifs.PNode == nil:
+      if ifs == nil:
         # Generate the right node depending on whether `n` is used as a stmt or
         # as an expr
         let kind = if n.typ != nil: nkIfExpr else: nkIfStmt
         ifs = newTransNode(kind, it.info, 0)
-        ifs.PNode.typ = n.typ
+        ifs.typ = n.typ
       ifs.add(e)
     of nkElse:
-      if ifs.PNode == nil: result.add(e)
+      if ifs == nil: result.add(e)
       else: ifs.add(e)
     else:
       result.add(e)
-  if ifs.PNode != nil:
+  if ifs != nil:
     var elseBranch = newTransNode(nkElse, n.info, 1)
     elseBranch[0] = ifs
     result.add(elseBranch)
-  elif result.PNode.lastSon.kind != nkElse and not (
-      skipTypes(n.sons[0].typ, abstractVarRange).kind in
+  elif result.lastSon.kind != nkElse and not (
+      skipTypes(n[0].typ, abstractVarRange).kind in
         {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt64}):
     # fix a stupid code gen bug by normalizing:
     var elseBranch = newTransNode(nkElse, n.info, 1)
     elseBranch[0] = newTransNode(nkNilLit, n.info, 0)
-    add(result, elseBranch)
+    result.add(elseBranch)
 
-proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
+proc transformArrayAccess(c: PTransf, n: PNode): PNode =
   # 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
+  if n[0].kind == nkSym and n[0].sym.kind == skType:
+    result = n
   else:
     result = newTransNode(n)
-    for i in 0 ..< n.len:
-      result[i] = transform(c, skipConv(n.sons[i]))
+    for i in 0..<n.len:
+      result[i] = transform(c, skipConv(n[i]))
 
 proc getMergeOp(n: PNode): PSym =
   case n.kind
   of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
      nkCallStrLit:
-    if n.sons[0].kind == nkSym and n.sons[0].sym.magic == mConStrStr:
-      result = n.sons[0].sym
+    if n[0].kind == nkSym and n[0].sym.magic == mConStrStr:
+      result = n[0].sym
   else: discard
 
 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):
-    for i in 1 ..< len(a): flattenTreeAux(d, a.sons[i], op)
+    for i in 1..<a.len: flattenTreeAux(d, a[i], op)
   else:
-    addSon(d, copyTree(a))
+    d.add copyTree(a)
 
 proc flattenTree(root: PNode): PNode =
   let op = getMergeOp(root)
   if op != nil:
     result = copyNode(root)
-    addSon(result, copyTree(root.sons[0]))
+    result.add copyTree(root[0])
     flattenTreeAux(result, root, op)
   else:
     result = root
 
-proc transformCall(c: PTransf, n: PNode): PTransNode =
+proc transformCall(c: PTransf, n: PNode): PNode =
   var n = flattenTree(n)
   let op = getMergeOp(n)
   let magic = getMagic(n)
   if op != nil and op.magic != mNone and n.len >= 3:
     result = newTransNode(nkCall, n, 0)
-    add(result, transform(c, n.sons[0]))
+    result.add(transform(c, n[0]))
     var j = 1
-    while j < len(n):
-      var a = transform(c, n.sons[j]).PNode
+    while j < n.len:
+      var a = transform(c, n[j])
       inc(j)
       if isConstExpr(a):
-        while (j < len(n)):
-          let b = transform(c, n.sons[j]).PNode
+        while (j < n.len):
+          let b = transform(c, n[j])
           if not isConstExpr(b): break
           a = evalOp(op.magic, n, a, b, nil, c.graph)
           inc(j)
-      add(result, a.PTransNode)
-    if len(result) == 2: result = result[1]
+      result.add(a)
+    if result.len == 2: result = result[1]
   elif magic == mAddr:
     result = newTransNode(nkAddr, n, 1)
-    result[0] = n[1].PTransNode
-    result = transformAddrDeref(c, result.PNode, nkDerefExpr, nkHiddenDeref)
+    result[0] = n[1]
+    result = transformAddrDeref(c, result, nkDerefExpr, nkHiddenDeref)
   elif magic in {mNBindSym, mTypeOf, mRunnableExamples}:
     # for bindSym(myconst) we MUST NOT perform constant folding:
-    result = n.PTransNode
+    result = n
   elif magic == mProcCall:
     # but do not change to its dispatcher:
     result = transformSons(c, n[1])
   elif magic == mStrToStr:
     result = transform(c, n[1])
   else:
-    let s = transformSons(c, n).PNode
+    let s = transformSons(c, n)
     # bugfix: check after 'transformSons' if it's still a method call:
     # use the dispatcher for the call:
-    if s.sons[0].kind == nkSym and s.sons[0].sym.kind == skMethod:
+    if s[0].kind == nkSym and s[0].sym.kind == skMethod:
       when false:
-        let t = lastSon(s.sons[0].sym.ast)
+        let t = lastSon(s[0].sym.ast)
         if t.kind != nkSym or sfDispatcher notin t.sym.flags:
-          methodDef(s.sons[0].sym, false)
-      result = methodCall(s, c.graph.config).PTransNode
+          methodDef(s[0].sym, false)
+      result = methodCall(s, c.graph.config)
     else:
-      result = s.PTransNode
+      result = s
 
-proc transformExceptBranch(c: PTransf, n: PNode): PTransNode =
+proc transformExceptBranch(c: PTransf, n: PNode): PNode =
   if n[0].isInfixAs() and not isImportedException(n[0][1].typ, c.graph.config):
     let excTypeNode = n[0][1]
     let actions = newTransNode(nkStmtListExpr, n[1], 2)
     # Generating `let exc = (excType)(getCurrentException())`
     # -> getCurrentException()
-    let excCall = PTransNode(callCodegenProc(c.graph, "getCurrentException"))
+    let excCall = callCodegenProc(c.graph, "getCurrentException")
     # -> (excType)
     let convNode = newTransNode(nkHiddenSubConv, n[1].info, 2)
-    convNode[0] = PTransNode(newNodeI(nkEmpty, n.info))
+    convNode[0] = newNodeI(nkEmpty, n.info)
     convNode[1] = excCall
-    PNode(convNode).typ = excTypeNode.typ.toRef()
+    convNode.typ = excTypeNode.typ.toRef()
     # -> let exc = ...
     let identDefs = newTransNode(nkIdentDefs, n[1].info, 3)
-    identDefs[0] = PTransNode(n[0][2])
-    identDefs[1] = PTransNode(newNodeI(nkEmpty, n.info))
+    identDefs[0] = n[0][2]
+    identDefs[1] = newNodeI(nkEmpty, n.info)
     identDefs[2] = convNode
 
     let letSection = newTransNode(nkLetSection, n[1].info, 1)
@@ -839,26 +817,26 @@ proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
 
 proc commonOptimizations*(g: ModuleGraph; c: PSym, n: PNode): PNode =
   result = n
-  for i in 0 ..< n.safeLen:
-    result.sons[i] = commonOptimizations(g, c, n.sons[i])
+  for i in 0..<n.safeLen:
+    result[i] = commonOptimizations(g, c, n[i])
   var op = getMergeOp(n)
-  if (op != nil) and (op.magic != mNone) and (len(n) >= 3):
+  if (op != nil) and (op.magic != mNone) and (n.len >= 3):
     result = newNodeIT(nkCall, n.info, n.typ)
-    add(result, n.sons[0])
+    result.add(n[0])
     var args = newNode(nkArgList)
     flattenTreeAux(args, n, op)
     var j = 0
-    while j < len(args):
-      var a = args.sons[j]
+    while j < args.len:
+      var a = args[j]
       inc(j)
       if isConstExpr(a):
-        while j < len(args):
-          let b = args.sons[j]
+        while j < args.len:
+          let b = args[j]
           if not isConstExpr(b): break
           a = evalOp(op.magic, result, a, b, nil, g)
           inc(j)
-      add(result, a)
-    if len(result) == 2: result = result[1]
+      result.add(a)
+    if result.len == 2: result = result[1]
   else:
     var cnst = getConstExpr(c, n, g)
     # we inline constants if they are not complex constants:
@@ -904,7 +882,7 @@ proc hoistParamsUsedInDefault(c: PTransf, call, letSection, defExpr: PNode): PNo
       let hoisted = hoistParamsUsedInDefault(c, call, letSection, defExpr[i])
       if hoisted != nil: defExpr[i] = hoisted
 
-proc transform(c: PTransf, n: PNode): PTransNode =
+proc transform(c: PTransf, n: PNode): PNode =
   when false:
     var oldDeferAnchor: PNode
     if n.kind in {nkElifBranch, nkOfBranch, nkExceptBranch, nkElifExpr,
@@ -917,24 +895,24 @@ proc transform(c: PTransf, n: PNode): PTransNode =
     result = transformSym(c, n)
   of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom:
     # nothing to be done for leaves:
-    result = PTransNode(n)
+    result = n
   of nkBracketExpr: result = transformArrayAccess(c, n)
   of procDefs:
-    var s = n.sons[namePos].sym
+    var s = n[namePos].sym
     if n.typ != nil and s.typ.callConv == ccClosure:
-      result = transformSym(c, n.sons[namePos])
+      result = transformSym(c, n[namePos])
       # use the same node as before if still a symbol:
-      if result.PNode.kind == nkSym: result = PTransNode(n)
+      if result.kind == nkSym: result = n
     else:
-      result = PTransNode(n)
+      result = n
   of nkMacroDef:
     # XXX no proper closure support yet:
     when false:
-      if n.sons[genericParamsPos].kind == nkEmpty:
-        var s = n.sons[namePos].sym
-        n.sons[bodyPos] = PNode(transform(c, s.getBody))
+      if n[genericParamsPos].kind == nkEmpty:
+        var s = n[namePos].sym
+        n[bodyPos] = transform(c, s.getBody)
         if n.kind == nkMethodDef: methodDef(s, false)
-    result = PTransNode(n)
+    result = n
   of nkForStmt:
     result = transformFor(c, n)
   of nkParForStmt:
@@ -949,38 +927,37 @@ proc transform(c: PTransf, n: PNode): PTransNode =
     result = transformSons(c, n)
     when false:
       let deferPart = newNodeI(nkFinally, n.info)
-      deferPart.add n.sons[0]
+      deferPart.add n[0]
       let tryStmt = newNodeI(nkTryStmt, n.info)
       if c.deferAnchor.isNil:
         tryStmt.add c.root
         c.root = tryStmt
-        result = PTransNode(tryStmt)
+        result = tryStmt
       else:
         # modify the corresponding *action*, don't rely on nkStmtList:
-        let L = c.deferAnchor.len-1
-        tryStmt.add c.deferAnchor.sons[L]
-        c.deferAnchor.sons[L] = tryStmt
+        tryStmt.add c.deferAnchor[^1]
+        c.deferAnchor[^1] = tryStmt
         result = newTransNode(nkCommentStmt, n.info, 0)
-      tryStmt.addSon(deferPart)
+      tryStmt.add deferPart
       # disable the original 'defer' statement:
       n.kind = nkEmpty
   of nkContinueStmt:
-    result = PTransNode(newNodeI(nkBreakStmt, n.info))
+    result = newNodeI(nkBreakStmt, n.info)
     var labl = c.contSyms[c.contSyms.high]
-    add(result, PTransNode(newSymNode(labl)))
+    result.add(newSymNode(labl))
   of nkBreakStmt: result = transformBreak(c, n)
   of nkCallKinds:
     result = transformCall(c, n)
-    var call = result.PNode
+    var call = result
     if nfDefaultRefsParam in call.flags:
       # We've found a default value that references another param.
       # See the notes in `hoistParamsUsedInDefault` for more details.
       var hoistedParams = newNodeI(nkLetSection, call.info, 0)
-      for i in 1 ..< call.len:
+      for i in 1..<call.len:
         let hoisted = hoistParamsUsedInDefault(c, call, hoistedParams, call[i])
         if hoisted != nil: call[i] = hoisted
-      result = newTree(nkStmtListExpr, hoistedParams, call).PTransNode
-      PNode(result).typ = call.typ
+      result = newTree(nkStmtListExpr, hoistedParams, call)
+      result.typ = call.typ
   of nkAddr, nkHiddenAddr:
     result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref)
   of nkDerefExpr, nkHiddenDeref:
@@ -988,22 +965,22 @@ proc transform(c: PTransf, n: PNode): PTransNode =
   of nkHiddenStdConv, nkHiddenSubConv, nkConv:
     result = transformConv(c, n)
   of nkDiscardStmt:
-    result = PTransNode(n)
-    if n.sons[0].kind != nkEmpty:
+    result = n
+    if n[0].kind != nkEmpty:
       result = transformSons(c, n)
-      if isConstExpr(PNode(result).sons[0]):
+      if isConstExpr(result[0]):
         # ensure that e.g. discard "some comment" gets optimized away
         # completely:
-        result = PTransNode(newNode(nkCommentStmt))
+        result = newNode(nkCommentStmt)
   of nkCommentStmt, nkTemplateDef, nkImportStmt, nkStaticStmt,
       nkExportStmt, nkExportExceptStmt:
-    return n.PTransNode
+    return n
   of nkConstSection:
     # do not replace ``const c = 3`` with ``const 3 = 3``
     return transformConstSection(c, n)
   of nkTypeSection, nkTypeOfExpr:
     # no need to transform type sections:
-    return PTransNode(n)
+    return n
   of nkVarSection, nkLetSection:
     if c.inlining > 0:
       # we need to copy the variables for multiple yield statements:
@@ -1018,22 +995,22 @@ proc transform(c: PTransf, n: PNode): PTransNode =
   of nkAsgn:
     result = transformAsgn(c, n)
   of nkIdentDefs, nkConstDef:
-    result = PTransNode(n)
+    result = n
     result[0] = transform(c, n[0])
     # Skip the second son since it only contains an unsemanticized copy of the
     # variable type used by docgen
     result[2] = transform(c, n[2])
     # XXX comment handling really sucks:
     if importantComments(c.graph.config):
-      PNode(result).comment = n.comment
+      result.comment = n.comment
   of nkClosure:
     # it can happen that for-loop-inlining produced a fresh
     # set of variables, including some computed environment
     # (bug #2604). We need to patch this environment here too:
     let a = n[1]
     if a.kind == nkSym:
-      n.sons[1] = transformSymAux(c, a)
-    return PTransNode(n)
+      n[1] = transformSymAux(c, a)
+    return n
   of nkExceptBranch:
     result = transformExceptBranch(c, n)
   else:
@@ -1046,10 +1023,10 @@ proc transform(c: PTransf, n: PNode): PTransNode =
   let exprIsPointerCast = n.kind in {nkCast, nkConv, nkHiddenStdConv} and
                           n.typ.kind == tyPointer
   if not exprIsPointerCast:
-    var cnst = getConstExpr(c.module, PNode(result), c.graph)
+    var cnst = getConstExpr(c.module, result, c.graph)
     # we inline constants if they are not complex constants:
     if cnst != nil and not dontInlineConstant(n, cnst):
-      result = PTransNode(cnst) # do not miss an optimization
+      result = cnst # do not miss an optimization
 
 proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
   # Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
@@ -1057,7 +1034,7 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
   # nodes into an empty node.
   if nfTransf in n.flags: return n
   pushTransCon(c, newTransCon(owner))
-  result = PNode(transform(c, n))
+  result = transform(c, n)
   popTransCon(c)
   incl(result.flags, nfTransf)
 
@@ -1088,22 +1065,22 @@ proc liftDeferAux(n: PNode) =
       goOn = false
       let last = n.len-1
       for i in 0..last:
-        if n.sons[i].kind == nkDefer:
-          let deferPart = newNodeI(nkFinally, n.sons[i].info)
-          deferPart.add n.sons[i].sons[0]
-          var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
-          var body = newNodeI(n.kind, n.sons[i].info)
+        if n[i].kind == nkDefer:
+          let deferPart = newNodeI(nkFinally, n[i].info)
+          deferPart.add n[i][0]
+          var tryStmt = newNodeI(nkTryStmt, n[i].info)
+          var body = newNodeI(n.kind, n[i].info)
           if i < last:
             body.sons = n.sons[(i+1)..last]
-          tryStmt.addSon(body)
-          tryStmt.addSon(deferPart)
-          n.sons[i] = tryStmt
+          tryStmt.add body
+          tryStmt.add deferPart
+          n[i] = tryStmt
           n.sons.setLen(i+1)
-          n.typ = n.sons[i].typ
+          n.typ = n[i].typ
           goOn = true
           break
   for i in 0..n.safeLen-1:
-    liftDeferAux(n.sons[i])
+    liftDeferAux(n[i])
 
 template liftDefer(c, root) =
   if c.deferDetected:
diff --git a/compiler/trees.nim b/compiler/trees.nim
index fd06425cb..4e6461b51 100644
--- a/compiler/trees.nim
+++ b/compiler/trees.nim
@@ -44,9 +44,9 @@ proc exprStructuralEquivalent*(a, b: PNode; strictSymEquality=false): bool =
     of nkCommentStmt: result = a.comment == b.comment
     of nkEmpty, nkNilLit, nkType: result = true
     else:
-      if len(a) == len(b):
-        for i in 0 ..< len(a):
-          if not exprStructuralEquivalent(a.sons[i], b.sons[i],
+      if a.len == b.len:
+        for i in 0..<a.len:
+          if not exprStructuralEquivalent(a[i], b[i],
                                           strictSymEquality): return
         result = true
 
@@ -68,16 +68,16 @@ proc sameTree*(a, b: PNode): bool =
     of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
     of nkEmpty, nkNilLit, nkType: result = true
     else:
-      if len(a) == len(b):
-        for i in 0 ..< len(a):
-          if not sameTree(a.sons[i], b.sons[i]): return
+      if a.len == b.len:
+        for i in 0..<a.len:
+          if not sameTree(a[i], b[i]): return
         result = true
 
 proc getMagic*(op: PNode): TMagic =
   case op.kind
   of nkCallKinds:
-    case op.sons[0].kind
-    of nkSym: result = op.sons[0].sym.magic
+    case op[0].kind
+    of nkSym: result = op[0].sym.magic
     else: result = mNone
   else: result = mNone
 
@@ -87,7 +87,7 @@ proc isConstExpr*(n: PNode): bool =
 
 proc isCaseObj*(n: PNode): bool =
   if n.kind == nkRecCase: return true
-  for i in 0..<safeLen(n):
+  for i in 0..<n.safeLen:
     if n[i].isCaseObj: return true
 
 proc isDeepConstExpr*(n: PNode): bool =
@@ -95,10 +95,10 @@ proc isDeepConstExpr*(n: PNode): bool =
   of nkCharLit..nkNilLit:
     result = true
   of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
-    result = isDeepConstExpr(n.sons[1])
+    result = isDeepConstExpr(n[1])
   of nkCurly, nkBracket, nkPar, nkTupleConstr, nkObjConstr, nkClosure, nkRange:
-    for i in ord(n.kind == nkObjConstr) ..< n.len:
-      if not isDeepConstExpr(n.sons[i]): return false
+    for i in ord(n.kind == nkObjConstr)..<n.len:
+      if not isDeepConstExpr(n[i]): return false
     if n.typ.isNil: result = true
     else:
       let t = n.typ.skipTypes({tyGenericInst, tyDistinct, tyAlias, tySink, tyOwned})
@@ -117,7 +117,7 @@ proc isRange*(n: PNode): bool {.inline.} =
       result = true
 
 proc whichPragma*(n: PNode): TSpecialWord =
-  let key = if n.kind in nkPragmaCallKinds and n.len > 0: n.sons[0] else: n
+  let key = if n.kind in nkPragmaCallKinds and n.len > 0: n[0] else: n
   if key.kind == nkIdent: result = whichKeyword(key.ident)
 
 proc findPragma*(n: PNode, which: TSpecialWord): PNode =
@@ -127,13 +127,13 @@ proc findPragma*(n: PNode, which: TSpecialWord): PNode =
         return son
 
 proc effectSpec*(n: PNode, effectType: TSpecialWord): PNode =
-  for i in 0 ..< len(n):
-    var it = n.sons[i]
+  for i in 0..<n.len:
+    var it = n[i]
     if it.kind == nkExprColonExpr and whichPragma(it) == effectType:
-      result = it.sons[1]
+      result = it[1]
       if result.kind notin {nkCurly, nkBracket}:
         result = newNodeI(nkCurly, result.info)
-        result.add(it.sons[1])
+        result.add(it[1])
       return
 
 proc unnestStmts(n, result: PNode) =
@@ -146,8 +146,8 @@ proc flattenStmts*(n: PNode): PNode =
   result = newNodeI(nkStmtList, n.info)
   unnestStmts(n, result)
   if result.len == 1:
-    result = result.sons[0]
+    result = result[0]
 
 proc extractRange*(k: TNodeKind, n: PNode, a, b: int): PNode =
   result = newNodeI(k, n.info, b-a+1)
-  for i in 0 .. b-a: result.sons[i] = n.sons[i+a]
+  for i in 0..b-a: result[i] = n[i+a]
diff --git a/compiler/treetab.nim b/compiler/treetab.nim
index f346d8d97..82df4cece 100644
--- a/compiler/treetab.nim
+++ b/compiler/treetab.nim
@@ -31,8 +31,8 @@ proc hashTree(n: PNode): Hash =
   of nkStrLit..nkTripleStrLit:
     result = result !& hash(n.strVal)
   else:
-    for i in 0 ..< len(n):
-      result = result !& hashTree(n.sons[i])
+    for i in 0..<n.len:
+      result = result !& hashTree(n[i])
 
 proc treesEquivalent(a, b: PNode): bool =
   if a == b:
@@ -46,9 +46,9 @@ proc treesEquivalent(a, b: PNode): bool =
     of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
     of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
     else:
-      if len(a) == len(b):
-        for i in 0 ..< len(a):
-          if not treesEquivalent(a.sons[i], b.sons[i]): return
+      if a.len == b.len:
+        for i in 0..<a.len:
+          if not treesEquivalent(a[i], b[i]): return
         result = true
     if result: result = sameTypeOrNil(a.typ, b.typ)
 
@@ -82,9 +82,9 @@ proc nodeTablePut*(t: var TNodeTable, key: PNode, val: int) =
     assert(t.data[index].key != nil)
     t.data[index].val = val
   else:
-    if mustRehash(len(t.data), t.counter):
-      newSeq(n, len(t.data) * GrowthFactor)
-      for i in 0 .. high(t.data):
+    if mustRehash(t.data.len, t.counter):
+      newSeq(n, t.data.len * GrowthFactor)
+      for i in 0..high(t.data):
         if t.data[i].key != nil:
           nodeTableRawInsert(n, t.data[i].h, t.data[i].key, t.data[i].val)
       swap(t.data, n)
@@ -99,9 +99,9 @@ proc nodeTableTestOrSet*(t: var TNodeTable, key: PNode, val: int): int =
     assert(t.data[index].key != nil)
     result = t.data[index].val
   else:
-    if mustRehash(len(t.data), t.counter):
-      newSeq(n, len(t.data) * GrowthFactor)
-      for i in 0 .. high(t.data):
+    if mustRehash(t.data.len, t.counter):
+      newSeq(n, t.data.len * GrowthFactor)
+      for i in 0..high(t.data):
         if t.data[i].key != nil:
           nodeTableRawInsert(n, t.data[i].h, t.data[i].key, t.data[i].val)
       swap(t.data, n)
diff --git a/compiler/types.nim b/compiler/types.nim
index 022995fa3..db5a7d70e 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -28,7 +28,7 @@ proc typeToString*(typ: PType; prefer: TPreferedDesc = preferName): string
 template `$`*(typ: PType): string = typeToString(typ)
 
 proc base*(t: PType): PType =
-  result = t.sons[0]
+  result = t[0]
 
 # ------------------- type iterator: ----------------------------------------
 type
@@ -79,8 +79,8 @@ proc invalidGenericInst*(f: PType): bool =
 
 proc isPureObject*(typ: PType): bool =
   var t = typ
-  while t.kind == tyObject and t.sons[0] != nil:
-    t = t.sons[0].skipTypes(skipPtrs)
+  while t.kind == tyObject and t[0] != nil:
+    t = t[0].skipTypes(skipPtrs)
   result = t.sym != nil and sfPure in t.sym.flags
 
 proc isUnsigned*(t: PType): bool =
@@ -98,7 +98,7 @@ proc getOrdValue*(n: PNode; onError = high(Int128)): Int128 =
     toInt128(n.intVal)
   of nkNilLit:
     int128.Zero
-  of nkHiddenStdConv: getOrdValue(n.sons[1], onError)
+  of nkHiddenStdConv: getOrdValue(n[1], onError)
   else:
     # XXX: The idea behind the introduction of int128 was to finally
     # have all calculations numerically far away from any
@@ -110,13 +110,13 @@ proc getOrdValue64*(n: PNode): BiggestInt {.deprecated: "use getOrdvalue".} =
   case n.kind
   of nkCharLit..nkUInt64Lit: n.intVal
   of nkNilLit: 0
-  of nkHiddenStdConv: getOrdValue64(n.sons[1])
+  of nkHiddenStdConv: getOrdValue64(n[1])
   else: high(BiggestInt)
 
 proc getFloatValue*(n: PNode): BiggestFloat =
   case n.kind
   of nkFloatLiterals: n.floatVal
-  of nkHiddenStdConv: getFloatValue(n.sons[1])
+  of nkHiddenStdConv: getFloatValue(n[1])
   else: NaN
 
 proc isIntLit*(t: PType): bool {.inline.} =
@@ -132,18 +132,18 @@ proc getProcHeader*(conf: ConfigRef; sym: PSym; prefer: TPreferedDesc = preferNa
   if sym.kind in routineKinds:
     result.add '('
     var n = sym.typ.n
-    for i in 1 ..< len(n):
-      let p = n.sons[i]
+    for i in 1..<n.len:
+      let p = n[i]
       if p.kind == nkSym:
-        add(result, p.sym.name.s)
-        add(result, ": ")
-        add(result, typeToString(p.sym.typ, prefer))
-        if i != len(n)-1: add(result, ", ")
+        result.add(p.sym.name.s)
+        result.add(": ")
+        result.add(typeToString(p.sym.typ, prefer))
+        if i != n.len-1: result.add(", ")
       else:
         result.add renderTree(p)
-    add(result, ')')
-    if n.sons[0].typ != nil:
-      result.add(": " & typeToString(n.sons[0].typ, prefer))
+    result.add(')')
+    if n[0].typ != nil:
+      result.add(": " & typeToString(n[0].typ, prefer))
   if getDeclarationPath:
     result.add " [declared in "
     result.add(conf$sym.info)
@@ -153,7 +153,7 @@ proc elemType*(t: PType): PType =
   assert(t != nil)
   case t.kind
   of tyGenericInst, tyDistinct, tyAlias, tySink: result = elemType(lastSon(t))
-  of tyArray: result = t.sons[1]
+  of tyArray: result = t[1]
   of tyError: result = t
   else: result = t.lastSon
   assert(result != nil)
@@ -180,8 +180,8 @@ proc iterOverNode(marker: var IntSet, n: PNode, iter: TTypeIter,
       # a leaf
       result = iterOverTypeAux(marker, n.typ, iter, closure)
     else:
-      for i in 0 ..< len(n):
-        result = iterOverNode(marker, n.sons[i], iter, closure)
+      for i in 0..<n.len:
+        result = iterOverNode(marker, n[i], iter, closure)
         if result: return
 
 proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter,
@@ -195,8 +195,8 @@ proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter,
     of tyGenericInst, tyGenericBody, tyAlias, tySink, tyInferred:
       result = iterOverTypeAux(marker, lastSon(t), iter, closure)
     else:
-      for i in 0 ..< len(t):
-        result = iterOverTypeAux(marker, t.sons[i], iter, closure)
+      for i in 0..<t.len:
+        result = iterOverTypeAux(marker, t[i], iter, closure)
         if result: return
       if t.n != nil and t.kind != tyProc: result = iterOverNode(marker, t.n, iter, closure)
 
@@ -212,17 +212,17 @@ proc searchTypeNodeForAux(n: PNode, p: TTypePredicate,
   result = false
   case n.kind
   of nkRecList:
-    for i in 0 ..< len(n):
-      result = searchTypeNodeForAux(n.sons[i], p, marker)
+    for i in 0..<n.len:
+      result = searchTypeNodeForAux(n[i], p, marker)
       if result: return
   of nkRecCase:
-    assert(n.sons[0].kind == nkSym)
-    result = searchTypeNodeForAux(n.sons[0], p, marker)
+    assert(n[0].kind == nkSym)
+    result = searchTypeNodeForAux(n[0], p, marker)
     if result: return
-    for i in 1 ..< len(n):
-      case n.sons[i].kind
+    for i in 1..<n.len:
+      case n[i].kind
       of nkOfBranch, nkElse:
-        result = searchTypeNodeForAux(lastSon(n.sons[i]), p, marker)
+        result = searchTypeNodeForAux(lastSon(n[i]), p, marker)
         if result: return
       else: discard
   of nkSym:
@@ -239,14 +239,14 @@ proc searchTypeForAux(t: PType, predicate: TTypePredicate,
   if result: return
   case t.kind
   of tyObject:
-    if t.sons[0] != nil:
-      result = searchTypeForAux(t.sons[0].skipTypes(skipPtrs), predicate, marker)
+    if t[0] != nil:
+      result = searchTypeForAux(t[0].skipTypes(skipPtrs), predicate, marker)
     if not result: result = searchTypeNodeForAux(t.n, predicate, marker)
   of tyGenericInst, tyDistinct, tyAlias, tySink:
     result = searchTypeForAux(lastSon(t), predicate, marker)
   of tyArray, tySet, tyTuple:
-    for i in 0 ..< len(t):
-      result = searchTypeForAux(t.sons[i], predicate, marker)
+    for i in 0..<t.len:
+      result = searchTypeForAux(t[i], predicate, marker)
       if result: return
   else:
     discard
@@ -262,7 +262,7 @@ proc containsObject*(t: PType): bool =
   result = searchTypeFor(t, isObjectPredicate)
 
 proc isObjectWithTypeFieldPredicate(t: PType): bool =
-  result = t.kind == tyObject and t.sons[0] == nil and
+  result = t.kind == tyObject and t[0] == nil and
       not (t.sym != nil and {sfPure, sfInfixCall} * t.sym.flags != {}) and
       tfFinal notin t.flags
 
@@ -282,8 +282,8 @@ proc analyseObjectWithTypeFieldAux(t: PType,
     if t.n != nil:
       if searchTypeNodeForAux(t.n, isObjectWithTypeFieldPredicate, marker):
         return frEmbedded
-    for i in 0 ..< len(t):
-      var x = t.sons[i]
+    for i in 0..<t.len:
+      var x = t[i]
       if x != nil: x = x.skipTypes(skipPtrs)
       res = analyseObjectWithTypeFieldAux(x, marker)
       if res == frEmbedded:
@@ -294,8 +294,8 @@ proc analyseObjectWithTypeFieldAux(t: PType,
   of tyGenericInst, tyDistinct, tyAlias, tySink:
     result = analyseObjectWithTypeFieldAux(lastSon(t), marker)
   of tyArray, tyTuple:
-    for i in 0 ..< len(t):
-      res = analyseObjectWithTypeFieldAux(t.sons[i], marker)
+    for i in 0..<t.len:
+      res = analyseObjectWithTypeFieldAux(t[i], marker)
       if res != frNone:
         return frEmbedded
   else:
@@ -344,8 +344,8 @@ proc canFormAcycleNode(marker: var IntSet, n: PNode, startId: int): bool =
       of nkNone..nkNilLit:
         discard
       else:
-        for i in 0 ..< len(n):
-          result = canFormAcycleNode(marker, n.sons[i], startId)
+        for i in 0..<n.len:
+          result = canFormAcycleNode(marker, n[i], startId)
           if result: return
 
 proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool =
@@ -355,8 +355,8 @@ proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool =
   case t.kind
   of tyTuple, tyObject, tyRef, tySequence, tyArray, tyOpenArray, tyVarargs:
     if not containsOrIncl(marker, t.id):
-      for i in 0 ..< len(t):
-        result = canFormAcycleAux(marker, t.sons[i], startId)
+      for i in 0..<t.len:
+        result = canFormAcycleAux(marker, t[i], startId)
         if result: return
       if t.n != nil: result = canFormAcycleNode(marker, t.n, startId)
     else:
@@ -391,8 +391,8 @@ proc mutateNode(marker: var IntSet, n: PNode, iter: TTypeMutator,
       # a leaf
       discard
     else:
-      for i in 0 ..< len(n):
-        addSon(result, mutateNode(marker, n.sons[i], iter, closure))
+      for i in 0..<n.len:
+        result.add mutateNode(marker, n[i], iter, closure)
 
 proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator,
                    closure: RootRef): PType =
@@ -400,8 +400,8 @@ proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator,
   if t == nil: return
   result = iter(t, closure)
   if not containsOrIncl(marker, t.id):
-    for i in 0 ..< len(t):
-      result.sons[i] = mutateTypeAux(marker, result.sons[i], iter, closure)
+    for i in 0..<t.len:
+      result[i] = mutateTypeAux(marker, result[i], iter, closure)
     if t.n != nil: result.n = mutateNode(marker, t.n, iter, closure)
   assert(result != nil)
 
@@ -418,7 +418,7 @@ proc valueToString(a: PNode): string =
 
 proc rangeToStr(n: PNode): string =
   assert(n.kind == nkRange)
-  result = valueToString(n.sons[0]) & ".." & valueToString(n.sons[1])
+  result = valueToString(n[0]) & ".." & valueToString(n[1])
 
 const
   typeToStr: array[TTypeKind, string] = ["None", "bool", "char", "empty",
@@ -441,7 +441,7 @@ const preferToResolveSymbols = {preferName, preferTypeName, preferModuleInfo,
   preferGenericArg, preferResolved, preferMixed}
 
 template bindConcreteTypeToUserTypeClass*(tc, concrete: PType) =
-  tc.sons.add concrete
+  tc.add concrete
   tc.flags.incl tfResolved
 
 # TODO: It would be a good idea to kill the special state of a resolved
@@ -473,8 +473,8 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
          sfAnon notin t.sym.flags and t.kind != tySequence:
       if t.kind == tyInt and isIntLit(t):
         result = t.sym.name.s & " literal(" & $t.n.intVal & ")"
-      elif t.kind == tyAlias and t.sons[0].kind != tyAlias:
-        result = typeToString(t.sons[0])
+      elif t.kind == tyAlias and t[0].kind != tyAlias:
+        result = typeToString(t[0])
       elif prefer in {preferResolved, preferMixed}:
         case t.kind
         of IntegralTypes + {tyFloat..tyFloat128} + {tyString, tyCString}:
@@ -512,25 +512,25 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
         else:
           result = "int literal(" & $t.n.intVal & ")"
     of tyGenericInst, tyGenericInvocation:
-      result = typeToString(t.sons[0]) & '['
-      for i in 1 ..< len(t)-ord(t.kind != tyGenericInvocation):
-        if i > 1: add(result, ", ")
-        add(result, typeToString(t.sons[i], preferGenericArg))
-      add(result, ']')
+      result = typeToString(t[0]) & '['
+      for i in 1..<t.len-ord(t.kind != tyGenericInvocation):
+        if i > 1: result.add(", ")
+        result.add(typeToString(t[i], preferGenericArg))
+      result.add(']')
     of tyGenericBody:
       result = typeToString(t.lastSon) & '['
-      for i in 0 .. len(t)-2:
-        if i > 0: add(result, ", ")
-        add(result, typeToString(t.sons[i], preferTypeName))
-      add(result, ']')
+      for i in 0..<t.len-1:
+        if i > 0: result.add(", ")
+        result.add(typeToString(t[i], preferTypeName))
+      result.add(']')
     of tyTypeDesc:
-      if t.sons[0].kind == tyNone: result = "typedesc"
-      else: result = "type " & typeToString(t.sons[0])
+      if t[0].kind == tyNone: result = "typedesc"
+      else: result = "type " & typeToString(t[0])
     of tyStatic:
       if prefer == preferGenericArg and t.n != nil:
         result = t.n.renderTree
       else:
-        result = "static[" & (if t.len > 0: typeToString(t.sons[0]) else: "") & "]"
+        result = "static[" & (if t.len > 0: typeToString(t[0]) else: "") & "]"
         if t.n != nil: result.add "(" & renderTree(t.n) & ")"
     of tyUserTypeClass:
       if t.sym != nil and t.sym.owner != nil:
@@ -560,9 +560,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
     of tyUserTypeClassInst:
       let body = t.base
       result = body.sym.name.s & "["
-      for i in 1 .. len(t) - 2:
-        if i > 1: add(result, ", ")
-        add(result, typeToString(t.sons[i]))
+      for i in 1..<t.len - 1:
+        if i > 1: result.add(", ")
+        result.add(typeToString(t[i]))
       result.add "]"
     of tyAnd:
       for i, son in t.sons:
@@ -575,7 +575,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
         if i < t.sons.high:
           result.add(" or ")
     of tyNot:
-      result = "not " & typeToString(t.sons[0])
+      result = "not " & typeToString(t[0])
     of tyUntyped:
       #internalAssert t.len == 0
       result = "untyped"
@@ -585,63 +585,63 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
       else:
         result = "type(" & renderTree(t.n) & ")"
     of tyArray:
-      if t.sons[0].kind == tyRange:
-        result = "array[" & rangeToStr(t.sons[0].n) & ", " &
-            typeToString(t.sons[1]) & ']'
+      if t[0].kind == tyRange:
+        result = "array[" & rangeToStr(t[0].n) & ", " &
+            typeToString(t[1]) & ']'
       else:
-        result = "array[" & typeToString(t.sons[0]) & ", " &
-            typeToString(t.sons[1]) & ']'
+        result = "array[" & typeToString(t[0]) & ", " &
+            typeToString(t[1]) & ']'
     of tyUncheckedArray:
-      result = "UncheckedArray[" & typeToString(t.sons[0]) & ']'
+      result = "UncheckedArray[" & typeToString(t[0]) & ']'
     of tySequence:
-      result = "seq[" & typeToString(t.sons[0]) & ']'
+      result = "seq[" & typeToString(t[0]) & ']'
     of tyOpt:
-      result = "opt[" & typeToString(t.sons[0]) & ']'
+      result = "opt[" & typeToString(t[0]) & ']'
     of tyOrdinal:
-      result = "ordinal[" & typeToString(t.sons[0]) & ']'
+      result = "ordinal[" & typeToString(t[0]) & ']'
     of tySet:
-      result = "set[" & typeToString(t.sons[0]) & ']'
+      result = "set[" & typeToString(t[0]) & ']'
     of tyOpenArray:
-      result = "openArray[" & typeToString(t.sons[0]) & ']'
+      result = "openArray[" & typeToString(t[0]) & ']'
     of tyDistinct:
-      result = "distinct " & typeToString(t.sons[0],
+      result = "distinct " & typeToString(t[0],
         if prefer == preferModuleInfo: preferModuleInfo else: preferTypeName)
     of tyTuple:
       # we iterate over t.sons here, because t.n may be nil
       if t.n != nil:
         result = "tuple["
-        assert(len(t.n) == len(t))
-        for i in 0 ..< len(t.n):
-          assert(t.n.sons[i].kind == nkSym)
-          add(result, t.n.sons[i].sym.name.s & ": " & typeToString(t.sons[i]))
-          if i < len(t.n) - 1: add(result, ", ")
-        add(result, ']')
-      elif len(t) == 0:
+        assert(t.n.len == t.len)
+        for i in 0..<t.n.len:
+          assert(t.n[i].kind == nkSym)
+          result.add(t.n[i].sym.name.s & ": " & typeToString(t[i]))
+          if i < t.n.len - 1: result.add(", ")
+        result.add(']')
+      elif t.len == 0:
         result = "tuple[]"
       else:
         if prefer == preferTypeName: result = "("
         else: result = "tuple of ("
-        for i in 0 ..< len(t):
-          add(result, typeToString(t.sons[i]))
-          if i < len(t) - 1: add(result, ", ")
-        add(result, ')')
+        for i in 0..<t.len:
+          result.add(typeToString(t[i]))
+          if i < t.len - 1: result.add(", ")
+        result.add(')')
     of tyPtr, tyRef, tyVar, tyLent:
       result = typeToStr[t.kind]
       if t.len >= 2:
         setLen(result, result.len-1)
         result.add '['
-        for i in 0 ..< len(t):
-          add(result, typeToString(t.sons[i]))
-          if i < len(t) - 1: add(result, ", ")
+        for i in 0..<t.len:
+          result.add(typeToString(t[i]))
+          if i < t.len - 1: result.add(", ")
         result.add ']'
       else:
-        result.add typeToString(t.sons[0])
+        result.add typeToString(t[0])
     of tyRange:
       result = "range "
       if t.n != nil and t.n.kind == nkRange:
         result.add rangeToStr(t.n)
       if prefer != preferExported:
-        result.add("(" & typeToString(t.sons[0]) & ")")
+        result.add("(" & typeToString(t[0]) & ")")
     of tyProc:
       result = if tfIterator in t.flags: "iterator "
                elif t.owner != nil:
@@ -654,31 +654,31 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
                 "proc "
       if tfUnresolved in t.flags: result.add "[*missing parameters*]"
       result.add "("
-      for i in 1 ..< len(t):
+      for i in 1..<t.len:
         if t.n != nil and i < t.n.len and t.n[i].kind == nkSym:
-          add(result, t.n[i].sym.name.s)
-          add(result, ": ")
-        add(result, typeToString(t.sons[i]))
-        if i < len(t) - 1: add(result, ", ")
-      add(result, ')')
-      if t.len > 0 and t.sons[0] != nil: add(result, ": " & typeToString(t.sons[0]))
+          result.add(t.n[i].sym.name.s)
+          result.add(": ")
+        result.add(typeToString(t[i]))
+        if i < t.len - 1: result.add(", ")
+      result.add(')')
+      if t.len > 0 and t[0] != nil: result.add(": " & typeToString(t[0]))
       var prag = if t.callConv == ccDefault: "" else: CallingConvToStr[t.callConv]
       if tfNoSideEffect in t.flags:
         addSep(prag)
-        add(prag, "noSideEffect")
+        prag.add("noSideEffect")
       if tfThread in t.flags:
         addSep(prag)
-        add(prag, "gcsafe")
+        prag.add("gcsafe")
       if t.lockLevel.ord != UnspecifiedLockLevel.ord:
         addSep(prag)
-        add(prag, "locks: " & $t.lockLevel)
-      if len(prag) != 0: add(result, "{." & prag & ".}")
+        prag.add("locks: " & $t.lockLevel)
+      if prag.len != 0: result.add("{." & prag & ".}")
     of tyVarargs:
-      result = typeToStr[t.kind] % typeToString(t.sons[0])
+      result = typeToStr[t.kind] % typeToString(t[0])
     of tySink:
-      result = "sink " & typeToString(t.sons[0])
+      result = "sink " & typeToString(t[0])
     of tyOwned:
-      result = "owned " & typeToString(t.sons[0])
+      result = "owned " & typeToString(t[0])
     else:
       result = typeToStr[t.kind]
     result.addTypeFlags(t)
@@ -688,12 +688,12 @@ proc firstOrd*(conf: ConfigRef; t: PType): Int128 =
   case t.kind
   of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy:
     result = Zero
-  of tySet, tyVar: result = firstOrd(conf, t.sons[0])
-  of tyArray: result = firstOrd(conf, t.sons[0])
+  of tySet, tyVar: result = firstOrd(conf, t[0])
+  of tyArray: result = firstOrd(conf, t[0])
   of tyRange:
     assert(t.n != nil)        # range directly given:
     assert(t.n.kind == nkRange)
-    result = getOrdValue(t.n.sons[0])
+    result = getOrdValue(t.n[0])
   of tyInt:
     if conf != nil and conf.target.intSize == 4:
       result = toInt128(-2147483648)
@@ -706,11 +706,11 @@ proc firstOrd*(conf: ConfigRef; t: PType): Int128 =
   of tyUInt..tyUInt64: result = Zero
   of tyEnum:
     # if basetype <> nil then return firstOrd of basetype
-    if len(t) > 0 and t.sons[0] != nil:
-      result = firstOrd(conf, t.sons[0])
+    if t.len > 0 and t[0] != nil:
+      result = firstOrd(conf, t[0])
     else:
-      assert(t.n.sons[0].kind == nkSym)
-      result = toInt128(t.n.sons[0].sym.position)
+      assert(t.n[0].kind == nkSym)
+      result = toInt128(t.n[0].sym.position)
   of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink,
      tyStatic, tyInferred, tyUserTypeClasses:
     result = firstOrd(conf, lastSon(t))
@@ -729,8 +729,8 @@ proc firstFloat*(t: PType): BiggestFloat =
   of tyRange:
     assert(t.n != nil)        # range directly given:
     assert(t.n.kind == nkRange)
-    getFloatValue(t.n.sons[0])
-  of tyVar: firstFloat(t.sons[0])
+    getFloatValue(t.n[0])
+  of tyVar: firstFloat(t[0])
   of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink,
      tyStatic, tyInferred, tyUserTypeClasses:
     firstFloat(lastSon(t))
@@ -742,12 +742,12 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 =
   case t.kind
   of tyBool: result = toInt128(1'u)
   of tyChar: result = toInt128(255'u)
-  of tySet, tyVar: result = lastOrd(conf, t.sons[0])
-  of tyArray: result = lastOrd(conf, t.sons[0])
+  of tySet, tyVar: result = lastOrd(conf, t[0])
+  of tyArray: result = lastOrd(conf, t[0])
   of tyRange:
     assert(t.n != nil)        # range directly given:
     assert(t.n.kind == nkRange)
-    result = getOrdValue(t.n.sons[1])
+    result = getOrdValue(t.n[1])
   of tyInt:
     if conf != nil and conf.target.intSize == 4: result = toInt128(0x7FFFFFFF)
     else: result = toInt128(0x7FFFFFFFFFFFFFFF'u64)
@@ -766,8 +766,8 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 =
   of tyUInt64:
     result = toInt128(0xFFFFFFFFFFFFFFFF'u64)
   of tyEnum:
-    assert(t.n.sons[len(t.n) - 1].kind == nkSym)
-    result = toInt128(t.n.sons[len(t.n) - 1].sym.position)
+    assert(t.n[^1].kind == nkSym)
+    result = toInt128(t.n[^1].sym.position)
   of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink,
      tyStatic, tyInferred, tyUserTypeClasses:
     result = lastOrd(conf, lastSon(t))
@@ -784,11 +784,11 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 =
 proc lastFloat*(t: PType): BiggestFloat =
   case t.kind
   of tyFloat..tyFloat128: Inf
-  of tyVar: lastFloat(t.sons[0])
+  of tyVar: lastFloat(t[0])
   of tyRange:
     assert(t.n != nil)        # range directly given:
     assert(t.n.kind == nkRange)
-    getFloatValue(t.n.sons[1])
+    getFloatValue(t.n[1])
   of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink,
      tyStatic, tyInferred, tyUserTypeClasses:
     lastFloat(lastSon(t))
@@ -799,13 +799,13 @@ proc lastFloat*(t: PType): BiggestFloat =
 proc floatRangeCheck*(x: BiggestFloat, t: PType): bool =
   case t.kind
   # This needs to be special cased since NaN is never
-  # part of firstFloat(t) .. lastFloat(t)
+  # part of firstFloat(t)..lastFloat(t)
   of tyFloat..tyFloat128:
     true
   of tyRange:
-    x in firstFloat(t) .. lastFloat(t)
+    x in firstFloat(t)..lastFloat(t)
   of tyVar:
-    floatRangeCheck(x, t.sons[0])
+    floatRangeCheck(x, t[0])
   of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink,
      tyStatic, tyInferred, tyUserTypeClasses:
     floatRangeCheck(x, lastSon(t))
@@ -815,7 +815,7 @@ proc floatRangeCheck*(x: BiggestFloat, t: PType): bool =
 
 proc lengthOrd*(conf: ConfigRef; t: PType): Int128 =
   if t.skipTypes(tyUserTypeClasses).kind == tyDistinct:
-    result = lengthOrd(conf, t.sons[0])
+    result = lengthOrd(conf, t[0])
   else:
     let last = lastOrd(conf, t)
     let first = firstOrd(conf, t)
@@ -897,7 +897,7 @@ proc equalParam(a, b: PSym): TParamsEquality =
 proc sameConstraints(a, b: PNode): bool =
   if isNil(a) and isNil(b): return true
   if a.len != b.len: return false
-  for i in 1 ..< a.len:
+  for i in 1..<a.len:
     if not exprStructuralEquivalent(a[i].sym.constraint,
                                     b[i].sym.constraint):
       return false
@@ -905,13 +905,12 @@ proc sameConstraints(a, b: PNode): bool =
 
 proc equalParams(a, b: PNode): TParamsEquality =
   result = paramsEqual
-  var length = len(a)
-  if length != len(b):
+  if a.len != b.len:
     result = paramsNotEqual
   else:
-    for i in 1 ..< length:
-      var m = a.sons[i].sym
-      var n = b.sons[i].sym
+    for i in 1..<a.len:
+      var m = a[i].sym
+      var n = b[i].sym
       assert((m.kind == skParam) and (n.kind == skParam))
       case equalParam(m, n)
       of paramsNotEqual:
@@ -936,11 +935,11 @@ 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 len(a) == len(b):
+  if a.len == b.len:
     result = true
-    for i in 0 ..< len(a):
-      var x = a.sons[i]
-      var y = b.sons[i]
+    for i in 0..<a.len:
+      var x = a[i]
+      var y = b[i]
       if IgnoreTupleFields in c.flags:
         x = skipTypes(x, {tyRange, tyGenericInst, tyAlias})
         y = skipTypes(y, {tyRange, tyGenericInst, tyAlias})
@@ -948,11 +947,11 @@ proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
       result = sameTypeAux(x, y, c)
       if not result: return
     if a.n != nil and b.n != nil and IgnoreTupleFields notin c.flags:
-      for i in 0 ..< len(a.n):
+      for i in 0..<a.n.len:
         # 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
+        if a.n[i].kind == nkSym and b.n[i].kind == nkSym:
+          var x = a.n[i].sym
+          var y = b.n[i].sym
           result = x.name.id == y.name.id
           if not result: break
         else:
@@ -1011,24 +1010,24 @@ 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 len(a) == len(b):
-          for i in 0 ..< len(a):
-            if not sameObjectTree(a.sons[i], b.sons[i], c): return
+        if a.len == b.len:
+          for i in 0..<a.len:
+            if not sameObjectTree(a[i], b[i], c): return
           result = true
 
 proc sameObjectStructures(a, b: PType, c: var TSameTypeClosure): bool =
   # check base types:
-  if len(a) != len(b): return
-  for i in 0 ..< len(a):
-    if not sameTypeOrNilAux(a.sons[i], b.sons[i], c): return
+  if a.len != b.len: return
+  for i in 0..<a.len:
+    if not sameTypeOrNilAux(a[i], b[i], c): return
   if not sameObjectTree(a.n, b.n, c): return
   result = true
 
 proc sameChildrenAux(a, b: PType, c: var TSameTypeClosure): bool =
-  if len(a) != len(b): return false
+  if a.len != b.len: return false
   result = true
-  for i in 0 ..< len(a):
-    result = sameTypeOrNilAux(a.sons[i], b.sons[i], c)
+  for i in 0..<a.len:
+    result = sameTypeOrNilAux(a[i], b[i], c)
     if not result: return
 
 proc isGenericAlias*(t: PType): bool =
@@ -1061,11 +1060,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
     case c.cmp
     of dcEq: return false
     of dcEqIgnoreDistinct:
-      while a.kind == tyDistinct: a = a.sons[0]
-      while b.kind == tyDistinct: b = b.sons[0]
+      while a.kind == tyDistinct: a = a[0]
+      while b.kind == tyDistinct: b = b[0]
       if a.kind != b.kind: return false
     of dcEqOrDistinctOf:
-      while a.kind == tyDistinct: a = a.sons[0]
+      while a.kind == tyDistinct: a = a[0]
       if a.kind != b.kind: return false
 
   # this is required by tunique_type but makes no sense really:
@@ -1075,9 +1074,9 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
       rhs = y.skipGenericAlias
     if rhs.kind != tyGenericInst or lhs.base != rhs.base:
       return false
-    for i in 1 .. lhs.len - 2:
-      let ff = rhs.sons[i]
-      let aa = lhs.sons[i]
+    for i in 1..<lhs.len - 1:
+      let ff = rhs[i]
+      let aa = lhs[i]
       if not sameTypeAux(ff, aa, c): return false
     return true
 
@@ -1089,7 +1088,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
     result = exprStructuralEquivalent(a.n, b.n) and sameFlags(a, b)
     if result and a.len == b.len and a.len == 1:
       cycleCheck()
-      result = sameTypeAux(a.sons[0], b.sons[0], c)
+      result = sameTypeAux(a[0], b[0], c)
   of tyObject:
     ifFastObjectTypeCheckFailed(a, b):
       cycleCheck()
@@ -1099,9 +1098,9 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
     if c.cmp == dcEq:
       if sameFlags(a, b):
         ifFastObjectTypeCheckFailed(a, b):
-          result = sameTypeAux(a.sons[0], b.sons[0], c)
+          result = sameTypeAux(a[0], b[0], c)
     else:
-      result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b)
+      result = sameTypeAux(a[0], b[0], c) and sameFlags(a, b)
   of tyEnum, tyForward:
     # XXX generic enums do not make much sense, but require structural checking
     result = a.id == b.id and sameFlags(a, b)
@@ -1146,9 +1145,9 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
                ((ExactConstraints notin c.flags) or sameConstraints(a.n, b.n))
   of tyRange:
     cycleCheck()
-    result = sameTypeOrNilAux(a.sons[0], b.sons[0], c) and
-        sameValue(a.n.sons[0], b.n.sons[0]) and
-        sameValue(a.n.sons[1], b.n.sons[1])
+    result = sameTypeOrNilAux(a[0], b[0], c) and
+        sameValue(a.n[0], b.n[0]) and
+        sameValue(a.n[1], b.n[1])
   of tyGenericInst, tyAlias, tyInferred:
     cycleCheck()
     result = sameTypeAux(a.lastSon, b.lastSon, c)
@@ -1184,14 +1183,14 @@ proc inheritanceDiff*(a, b: PType): int =
   while x != nil:
     x = skipTypes(x, skipPtrs)
     if sameObjectTypes(x, b): return
-    x = x.sons[0]
+    x = x[0]
     dec(result)
   var y = b
   result = 0
   while y != nil:
     y = skipTypes(y, skipPtrs)
     if sameObjectTypes(y, a): return
-    y = y.sons[0]
+    y = y[0]
     inc(result)
   result = high(int)
 
@@ -1208,7 +1207,7 @@ proc commonSuperclass*(a, b: PType): PType =
   while x != nil:
     x = skipTypes(x, skipPtrs)
     ancestors.incl(x.id)
-    x = x.sons[0]
+    x = x[0]
   var y = b
   while y != nil:
     var t = y # bug #7818, save type before skip
@@ -1217,7 +1216,7 @@ proc commonSuperclass*(a, b: PType): PType =
       # bug #7818, defer the previous skipTypes
       if t.kind != tyGenericInst: t = y
       return t
-    y = y.sons[0]
+    y = y[0]
 
 type
   TTypeAllowedFlag* = enum
@@ -1243,8 +1242,8 @@ proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind,
       else:
         #if n.kind == nkRecCase and kind in {skProc, skFunc, skConst}:
         #  return n[0].typ
-        for i in 0 ..< len(n):
-          let it = n.sons[i]
+        for i in 0..<n.len:
+          let it = n[i]
           result = typeAllowedNode(marker, it, kind, flags)
           if result != nil: break
 
@@ -1253,8 +1252,8 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
   var a = a
   for k, i in pattern.items:
     if a.kind != k: return false
-    if i >= a.len or a.sons[i] == nil: return false
-    a = a.sons[i]
+    if i >= a.len or a[i] == nil: return false
+    a = a[i]
   result = a.kind == last
 
 proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
@@ -1273,16 +1272,16 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
     elif t.kind == tyLent and kind != skResult:
       result = t
     else:
-      var t2 = skipTypes(t.sons[0], abstractInst-{tyTypeDesc})
+      var t2 = skipTypes(t[0], abstractInst-{tyTypeDesc})
       case t2.kind
       of tyVar, tyLent:
         if taHeap notin flags: result = t2 # ``var var`` is illegal on the heap
       of tyOpenArray:
         if kind != skParam or taIsOpenArray in flags: result = t
-        else: result = typeAllowedAux(marker, t2.sons[0], kind, flags+{taIsOpenArray})
+        else: result = typeAllowedAux(marker, t2[0], kind, flags+{taIsOpenArray})
       of tyUncheckedArray:
         if kind != skParam: result = t
-        else: result = typeAllowedAux(marker, t2.sons[0], kind, flags)
+        else: result = typeAllowedAux(marker, t2[0], kind, flags)
       else:
         if kind notin {skParam, skResult}: result = t
         else: result = typeAllowedAux(marker, t2, kind, flags)
@@ -1291,11 +1290,11 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
       # only closure iterators my be assigned to anything.
       result = t
     let f = if kind in {skProc, skFunc}: flags+{taNoUntyped} else: flags
-    for i in 1 ..< len(t):
+    for i in 1..<t.len:
       if result != nil: break
-      result = typeAllowedAux(marker, t.sons[i], skParam, f-{taIsOpenArray})
-    if result.isNil and t.sons[0] != nil:
-      result = typeAllowedAux(marker, t.sons[0], skResult, flags)
+      result = typeAllowedAux(marker, t[i], skParam, f-{taIsOpenArray})
+    if result.isNil and t[0] != nil:
+      result = typeAllowedAux(marker, t[0], skResult, flags)
   of tyTypeDesc:
     # XXX: This is still a horrible idea...
     result = nil
@@ -1324,46 +1323,46 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
   of tyGenericInst, tyDistinct, tyAlias, tyInferred:
     result = typeAllowedAux(marker, lastSon(t), kind, flags)
   of tyRange:
-    if skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind notin
+    if skipTypes(t[0], abstractInst-{tyTypeDesc}).kind notin
       {tyChar, tyEnum, tyInt..tyFloat128, tyInt..tyUInt64}: result = t
   of tyOpenArray, tyVarargs, tySink:
     # you cannot nest openArrays/sinks/etc.
     if kind != skParam or taIsOpenArray in flags:
       result = t
     else:
-      result = typeAllowedAux(marker, t.sons[0], kind, flags+{taIsOpenArray})
+      result = typeAllowedAux(marker, t[0], kind, flags+{taIsOpenArray})
   of tyUncheckedArray:
     if kind != skParam and taHeap notin flags:
       result = t
     else:
       result = typeAllowedAux(marker, lastSon(t), kind, flags-{taHeap})
   of tySequence, tyOpt:
-    if t.sons[0].kind != tyEmpty:
-      result = typeAllowedAux(marker, t.sons[0], kind, flags+{taHeap})
+    if t[0].kind != tyEmpty:
+      result = typeAllowedAux(marker, t[0], kind, flags+{taHeap})
     elif kind in {skVar, skLet}:
-      result = t.sons[0]
+      result = t[0]
   of tyArray:
-    if t.sons[1].kind != tyEmpty:
-      result = typeAllowedAux(marker, t.sons[1], kind, flags)
+    if t[1].kind != tyEmpty:
+      result = typeAllowedAux(marker, t[1], kind, flags)
     elif kind in {skVar, skLet}:
-      result = t.sons[1]
+      result = t[1]
   of tyRef:
     if kind == skConst: result = t
     else: result = typeAllowedAux(marker, t.lastSon, kind, flags+{taHeap})
   of tyPtr:
     result = typeAllowedAux(marker, t.lastSon, kind, flags+{taHeap})
   of tySet:
-    for i in 0 ..< len(t):
-      result = typeAllowedAux(marker, t.sons[i], kind, flags)
+    for i in 0..<t.len:
+      result = typeAllowedAux(marker, t[i], kind, flags)
       if result != nil: break
   of tyObject, tyTuple:
     if kind in {skProc, skFunc, skConst} and
-        t.kind == tyObject and t.sons[0] != nil:
+        t.kind == tyObject and t[0] != nil:
       result = t
     else:
       let flags = flags+{taField}
-      for i in 0 ..< len(t):
-        result = typeAllowedAux(marker, t.sons[i], kind, flags)
+      for i in 0..<t.len:
+        result = typeAllowedAux(marker, t[i], kind, flags)
         if result != nil: break
       if result.isNil and t.n != nil:
         result = typeAllowedNode(marker, t.n, kind, flags)
@@ -1374,7 +1373,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
     # prevent cascading errors:
     result = nil
   of tyOwned:
-    if t.len == 1 and t.sons[0].skipTypes(abstractInst).kind in {tyRef, tyPtr, tyProc}:
+    if t.len == 1 and t[0].skipTypes(abstractInst).kind in {tyRef, tyPtr, tyProc}:
       result = typeAllowedAux(marker, t.lastSon, kind, flags+{taHeap})
     else:
       result = t
@@ -1394,7 +1393,7 @@ proc computeSize*(conf: ConfigRef; typ: PType): BiggestInt =
 proc getReturnType*(s: PSym): PType =
   # Obtains the return type of a iterator/proc/macro/template
   assert s.kind in skProcKinds
-  result = s.typ.sons[0]
+  result = s.typ[0]
 
 proc getAlign*(conf: ConfigRef; typ: PType): BiggestInt =
   computeSizeAlign(conf, typ)
@@ -1422,7 +1421,7 @@ proc containsGenericType*(t: PType): bool =
 
 proc baseOfDistinct*(t: PType): PType =
   if t.kind == tyDistinct:
-    result = t.sons[0]
+    result = t[0]
   else:
     result = copyType(t, t.owner, false)
     var parent: PType = nil
@@ -1431,7 +1430,7 @@ proc baseOfDistinct*(t: PType): PType =
       parent = it
       it = it.lastSon
     if it.kind == tyDistinct and parent != nil:
-      parent.sons[0] = it.sons[0]
+      parent[0] = it[0]
 
 proc safeInheritanceDiff*(a, b: PType): int =
   # same as inheritanceDiff but checks for tyError:
@@ -1462,29 +1461,29 @@ type
 proc compatibleEffects*(formal, actual: PType): EffectsCompat =
   # for proc type compatibility checking:
   assert formal.kind == tyProc and actual.kind == tyProc
-  if formal.n.sons[0].kind != nkEffectList or
-     actual.n.sons[0].kind != nkEffectList:
+  if formal.n[0].kind != nkEffectList or
+     actual.n[0].kind != nkEffectList:
     return efTagsUnknown
 
-  var spec = formal.n.sons[0]
+  var spec = formal.n[0]
   if spec.len != 0:
-    var real = actual.n.sons[0]
+    var real = actual.n[0]
 
-    let se = spec.sons[exceptionEffects]
+    let se = spec[exceptionEffects]
     # if 'se.kind == nkArgList' it is no formal type really, but a
     # computed effect and as such no spec:
     # 'r.msgHandler = if isNil(msgHandler): defaultMsgHandler else: msgHandler'
     if not isNil(se) and se.kind != nkArgList:
       # spec requires some exception or tag, but we don't know anything:
       if real.len == 0: return efRaisesUnknown
-      let res = compatibleEffectsAux(se, real.sons[exceptionEffects])
+      let res = compatibleEffectsAux(se, real[exceptionEffects])
       if not res: return efRaisesDiffer
 
-    let st = spec.sons[tagEffects]
+    let st = spec[tagEffects]
     if not isNil(st) and st.kind != nkArgList:
       # spec requires some exception or tag, but we don't know anything:
       if real.len == 0: return efTagsUnknown
-      let res = compatibleEffectsAux(st, real.sons[tagEffects])
+      let res = compatibleEffectsAux(st, real[tagEffects])
       if not res: return efTagsDiffer
   if formal.lockLevel.ord < 0 or
       actual.lockLevel.ord <= formal.lockLevel.ord:
@@ -1497,8 +1496,8 @@ proc isCompileTimeOnly*(t: PType): bool {.inline.} =
 
 proc containsCompileTimeOnly*(t: PType): bool =
   if isCompileTimeOnly(t): return true
-  for i in 0 ..< t.len:
-    if t.sons[i] != nil and isCompileTimeOnly(t.sons[i]):
+  for i in 0..<t.len:
+    if t[i] != nil and isCompileTimeOnly(t[i]):
       return true
   return false
 
@@ -1523,11 +1522,11 @@ proc skipConv*(n: PNode): PNode =
   of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
     # only skip the conversion if it doesn't lose too important information
     # (see bug #1334)
-    if n.sons[0].typ.classify == n.typ.classify:
-      result = n.sons[0]
+    if n[0].typ.classify == n.typ.classify:
+      result = n[0]
   of nkHiddenStdConv, nkHiddenSubConv, nkConv:
-    if n.sons[1].typ.classify == n.typ.classify:
-      result = n.sons[1]
+    if n[1].typ.classify == n.typ.classify:
+      result = n[1]
   else: discard
 
 proc skipHidden*(n: PNode): PNode =
@@ -1535,11 +1534,11 @@ proc skipHidden*(n: PNode): PNode =
   while true:
     case result.kind
     of nkHiddenStdConv, nkHiddenSubConv:
-      if result.sons[1].typ.classify == result.typ.classify:
-        result = result.sons[1]
+      if result[1].typ.classify == result.typ.classify:
+        result = result[1]
       else: break
     of nkHiddenDeref, nkHiddenAddr:
-      result = result.sons[0]
+      result = result[0]
     else: break
 
 proc skipConvTakeType*(n: PNode): PNode =
@@ -1549,9 +1548,9 @@ proc skipConvTakeType*(n: PNode): PNode =
 proc isEmptyContainer*(t: PType): bool =
   case t.kind
   of tyUntyped, tyNil: result = true
-  of tyArray: result = t.sons[1].kind == tyEmpty
+  of tyArray: result = t[1].kind == tyEmpty
   of tySet, tySequence, tyOpenArray, tyVarargs:
-    result = t.sons[0].kind == tyEmpty
+    result = t[0].kind == tyEmpty
   of tyGenericInst, tyAlias, tySink: result = isEmptyContainer(t.lastSon)
   else: result = false
 
@@ -1564,7 +1563,7 @@ proc takeType*(formal, arg: PType): PType =
   elif formal.kind in {tyOpenArray, tyVarargs, tySequence} and
       arg.isEmptyContainer:
     let a = copyType(arg.skipTypes({tyGenericInst, tyAlias}), arg.owner, keepId=false)
-    a.sons[ord(arg.kind == tyArray)] = formal.sons[0]
+    a[ord(arg.kind == tyArray)] = formal[0]
     result = a
   elif formal.kind in {tyTuple, tySet} and arg.kind == formal.kind:
     result = formal
@@ -1576,7 +1575,7 @@ proc skipHiddenSubConv*(n: PNode): PNode =
     # param: openArray[string] = []
     # [] is an array constructor of length 0 of type string!
     let formal = n.typ
-    result = n.sons[1]
+    result = n[1]
     let arg = result.typ
     let dest = takeType(formal, arg)
     if dest == arg and formal.kind != tyUntyped:
@@ -1640,8 +1639,8 @@ proc isException*(t: PType): bool =
   var t = t.skipTypes(abstractInst)
   while t.kind == tyObject:
     if t.sym != nil and t.sym.magic == mException: return true
-    if t.sons[0] == nil: break
-    t = skipTypes(t.sons[0], abstractPtrs)
+    if t[0] == nil: break
+    t = skipTypes(t[0], abstractPtrs)
   return false
 
 proc isSinkTypeForParam*(t: PType): bool =
diff --git a/compiler/typesrenderer.nim b/compiler/typesrenderer.nim
index 7084349e5..60f9f6603 100644
--- a/compiler/typesrenderer.nim
+++ b/compiler/typesrenderer.nim
@@ -19,7 +19,7 @@ proc renderPlainSymbolName*(n: PNode): string =
   ## for the HTML hyperlinks.
   case n.kind
   of nkPostfix, nkAccQuoted:
-    result = renderPlainSymbolName(n[n.len-1])
+    result = renderPlainSymbolName(n[^1])
   of nkIdent:
     result = n.ident.s
   of nkSym:
@@ -51,33 +51,33 @@ proc renderType(n: PNode): string =
     else:
       result = "ptr"
   of nkProcTy:
-    assert len(n) != 1
-    if len(n) > 1:
+    assert n.len != 1
+    if n.len > 1:
       let params = n[0]
       assert params.kind == nkFormalParams
-      assert len(params) > 0
+      assert params.len > 0
       result = "proc("
-      for i in 1 ..< len(params): result.add(renderType(params[i]) & ',')
-      result[len(result)-1] = ')'
+      for i in 1..<params.len: result.add(renderType(params[i]) & ',')
+      result[^1] = ')'
     else:
       result = "proc"
   of nkIdentDefs:
-    assert len(n) >= 3
-    let typePos = len(n) - 2
+    assert n.len >= 3
+    let typePos = n.len - 2
     let typeStr = renderType(n[typePos])
     result = typeStr
-    for i in 1 ..< typePos:
+    for i in 1..<typePos:
       assert n[i].kind == nkIdent
       result.add(',' & typeStr)
   of nkTupleTy:
     result = "tuple["
-    for i in 0 ..< len(n): result.add(renderType(n[i]) & ',')
-    result[len(result)-1] = ']'
+    for i in 0..<n.len: result.add(renderType(n[i]) & ',')
+    result[^1] = ']'
   of nkBracketExpr:
-    assert len(n) >= 2
+    assert n.len >= 2
     result = renderType(n[0]) & '['
-    for i in 1 ..< len(n): result.add(renderType(n[i]) & ',')
-    result[len(result)-1] = ']'
+    for i in 1..<n.len: result.add(renderType(n[i]) & ',')
+    result[^1] = ']'
   else: result = ""
 
 
@@ -89,10 +89,10 @@ proc renderParamTypes(found: var seq[string], n: PNode) =
   ## generator does include the information.
   case n.kind
   of nkFormalParams:
-    for i in 1 ..< len(n): renderParamTypes(found, n[i])
+    for i in 1..<n.len: renderParamTypes(found, n[i])
   of nkIdentDefs:
     # These are parameter names + type + default value node.
-    let typePos = len(n) - 2
+    let typePos = n.len - 2
     assert typePos > 0
     var typeStr = renderType(n[typePos])
     if typeStr.len < 1 and n[typePos+1].kind != nkEmpty:
@@ -100,7 +100,7 @@ proc renderParamTypes(found: var seq[string], n: PNode) =
       let typ = n[typePos+1].typ
       if not typ.isNil: typeStr = typeToString(typ, preferExported)
       if typeStr.len < 1: return
-    for i in 0 ..< typePos:
+    for i in 0..<typePos:
       found.add(typeStr)
   else:
     found.add($n)
diff --git a/compiler/vm.nim b/compiler/vm.nim
index ce473c12a..7e2ad692f 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -73,14 +73,14 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) =
     var line = toLinenumber(info)
     var col = toColumn(info)
     if line > 0:
-      add(s, '(')
-      add(s, $line)
-      add(s, ", ")
-      add(s, $(col + ColOffset))
-      add(s, ')')
+      s.add('(')
+      s.add($line)
+      s.add(", ")
+      s.add($(col + ColOffset))
+      s.add(')')
     if x.prc != nil:
-      for k in 1..max(1, 25-s.len): add(s, ' ')
-      add(s, x.prc.name.s)
+      for k in 1..max(1, 25-s.len): s.add(' ')
+      s.add(x.prc.name.s)
     msgWriteln(c.config, s)
 
 proc stackTraceImpl(c: PCtx, tos: PStackFrame, pc: int,
@@ -102,8 +102,8 @@ template stackTrace(c: PCtx, tos: PStackFrame, pc: int, msg: string) =
 
 proc bailOut(c: PCtx; tos: PStackFrame) =
   stackTrace(c, tos, c.exceptionInstr, "unhandled exception: " &
-             c.currentExceptionA.sons[3].skipColon.strVal &
-             " [" & c.currentExceptionA.sons[2].skipColon.strVal & "]")
+             c.currentExceptionA[3].skipColon.strVal &
+             " [" & c.currentExceptionA[2].skipColon.strVal & "]")
 
 when not defined(nimComputedGoto):
   {.pragma: computedGoto.}
@@ -200,9 +200,9 @@ proc copyValue(src: PNode): PNode =
   of nkIdent: result.ident = src.ident
   of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
   else:
-    newSeq(result.sons, len(src))
-    for i in 0 ..< len(src):
-      result.sons[i] = copyValue(src.sons[i])
+    newSeq(result.sons, src.len)
+    for i in 0..<src.len:
+      result[i] = copyValue(src[i])
 
 proc asgnComplex(x: var TFullReg, y: TFullReg) =
   if x.kind != y.kind:
@@ -358,7 +358,7 @@ proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int =
 
   # Traverse the stack starting from the end in order to execute the blocks in
   # the intended order
-  for i in 1 .. f.safePoints.len:
+  for i in 1..f.safePoints.len:
     var pc = f.safePoints[^i]
     # Skip the `except` blocks
     while c.code[pc].opcode == opcExcept:
@@ -378,12 +378,12 @@ proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType):
     of tyEnum:
       let n = styp.n
       let x = src.intVal.int
-      if x <% n.len and (let f = n.sons[x].sym; f.position == x):
+      if x <% n.len and (let f = n[x].sym; f.position == x):
         dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal
       else:
         for i in 0..<n.len:
-          if n.sons[i].kind != nkSym: internalError(c.config, "opConv for enum")
-          let f = n.sons[i].sym
+          if n[i].kind != nkSym: internalError(c.config, "opConv for enum")
+          let f = n[i].sym
           if f.position == x:
             dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal
             return
@@ -473,16 +473,16 @@ template handleJmpBack() {.dirty.} =
 proc recSetFlagIsRef(arg: PNode) =
   if arg.kind notin {nkStrLit..nkTripleStrLit}:
     arg.flags.incl(nfIsRef)
-  for i in 0 ..< arg.safeLen:
-    arg.sons[i].recSetFlagIsRef
+  for i in 0..<arg.safeLen:
+    arg[i].recSetFlagIsRef
 
 proc setLenSeq(c: PCtx; node: PNode; newLen: int; info: TLineInfo) =
   let typ = node.typ.skipTypes(abstractInst+{tyRange}-{tyTypeDesc})
   let oldLen = node.len
   setLen(node.sons, newLen)
   if oldLen < newLen:
-    for i in oldLen ..< newLen:
-      node.sons[i] = getNullValue(typ.sons[0], info, c.config)
+    for i in oldLen..<newLen:
+      node[i] = getNullValue(typ[0], info, c.config)
 
 const
   errNilAccess = "attempt to access a nil address"
@@ -603,7 +603,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         else:
           stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.strVal.len-1))
       elif src.kind notin {nkEmpty..nkFloat128Lit} and idx <% src.len:
-        regs[ra].node = src.sons[idx]
+        regs[ra].node = src[idx]
       else:
         stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.len-1))
     of opcLdArrAddr:
@@ -638,7 +638,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         else:
           stackTrace(c, tos, pc, formatErrorIndexBound(idx, arr.strVal.len-1))
       elif idx <% arr.len:
-        writeField(arr.sons[idx], regs[rc])
+        writeField(arr[idx], regs[rc])
       else:
         stackTrace(c, tos, pc, formatErrorIndexBound(idx, arr.len-1))
     of opcLdObj:
@@ -649,10 +649,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       of nkEmpty..nkNilLit:
         stackTrace(c, tos, pc, errNilAccess)
       of nkObjConstr:
-        let n = src.sons[rc + 1].skipColon
+        let n = src[rc + 1].skipColon
         regs[ra].node = n
       else:
-        let n = src.sons[rc]
+        let n = src[rc]
         regs[ra].node = n
     of opcLdObjAddr:
       # a = addr(b.c)
@@ -677,10 +677,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       let dest = regs[ra].node
       if dest.kind == nkNilLit:
         stackTrace(c, tos, pc, errNilAccess)
-      elif dest.sons[shiftedRb].kind == nkExprColonExpr:
-        writeField(dest.sons[shiftedRb].sons[1], regs[rc])
+      elif dest[shiftedRb].kind == nkExprColonExpr:
+        writeField(dest[shiftedRb][1], regs[rc])
       else:
-        writeField(dest.sons[shiftedRb], regs[rc])
+        writeField(dest[shiftedRb], regs[rc])
     of opcWrStrIdx:
       decodeBC(rkNode)
       let idx = regs[rb].intVal.int
@@ -712,7 +712,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         if regs[rb].node.kind == nkNilLit:
           stackTrace(c, tos, pc, errNilAccess)
         if regs[rb].node.kind == nkRefTy:
-          regs[ra].node = regs[rb].node.sons[0]
+          regs[ra].node = regs[rb].node[0]
         else:
           ensureKind(rkNode)
           regs[ra].node = regs[rb].node
@@ -802,20 +802,20 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       decodeB(rkNode)
       let b = regs[rb].regToNode
       if not inSet(regs[ra].node, b):
-        addSon(regs[ra].node, copyTree(b))
+        regs[ra].node.add copyTree(b)
     of opcInclRange:
       decodeBC(rkNode)
       var r = newNode(nkRange)
       r.add regs[rb].regToNode
       r.add regs[rc].regToNode
-      addSon(regs[ra].node, r.copyTree)
+      regs[ra].node.add r.copyTree
     of opcExcl:
       decodeB(rkNode)
       var b = newNodeIT(nkCurly, regs[ra].node.info, regs[ra].node.typ)
-      addSon(b, regs[rb].regToNode)
+      b.add regs[rb].regToNode
       var r = diffSets(c.config, regs[ra].node, b)
       discardSons(regs[ra].node)
-      for i in 0 ..< len(r): addSon(regs[ra].node, r.sons[i])
+      for i in 0..<r.len: regs[ra].node.add r[i]
     of opcCard:
       decodeB(rkInt)
       regs[ra].intVal = nimsets.cardSet(c.config, regs[rb].node)
@@ -1109,7 +1109,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       let rc = instr.regC
       let bb = regs[rb].node
       let isClosure = bb.kind == nkTupleConstr
-      let prc = if not isClosure: bb.sym else: bb.sons[0].sym
+      let prc = if not isClosure: bb.sym else: bb[0].sym
       if prc.offset < -1:
         # it's a callback:
         c.callbacks[-prc.offset-2].value(
@@ -1125,7 +1125,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
           if prc.position - 1 < 0:
             globalError(c.config, c.debug[pc],
               "VM call invalid: prc.position: " & $prc.position)
-          let prcValue = c.globals.sons[prc.position-1]
+          let prcValue = c.globals[prc.position-1]
           if prcValue.kind == nkEmpty:
             globalError(c.config, c.debug[pc], "cannot run " & prc.name.s)
           var slots2: TNodeSeq
@@ -1147,13 +1147,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         #echo "new pc ", newPc, " calling: ", prc.name.s
         var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos)
         newSeq(newFrame.slots, prc.offset+ord(isClosure))
-        if not isEmptyType(prc.typ.sons[0]):
-          putIntoReg(newFrame.slots[0], getNullValue(prc.typ.sons[0], prc.info, c.config))
-        for i in 1 .. rc-1:
+        if not isEmptyType(prc.typ[0]):
+          putIntoReg(newFrame.slots[0], getNullValue(prc.typ[0], prc.info, c.config))
+        for i in 1..rc-1:
           newFrame.slots[i] = regs[rb+i]
         if isClosure:
           newFrame.slots[rc].kind = rkNode
-          newFrame.slots[rc].node = regs[rb].node.sons[1]
+          newFrame.slots[rc].node = regs[rb].node[1]
         tos = newFrame
         move(regs, newFrame.slots)
         # -1 for the following 'inc pc'
@@ -1166,7 +1166,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
                             c.module
         var macroCall = newNodeI(nkCall, c.debug[pc])
         macroCall.add(newSymNode(prc))
-        for i in 1 .. rc-1:
+        for i in 1..rc-1:
           let node = regs[rb+i].regToNode
           node.info = c.debug[pc]
           macroCall.add(node)
@@ -1197,8 +1197,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       # we know the next instruction is a 'fjmp':
       let branch = c.constants[instr.regBx-wordExcess]
       var cond = false
-      for j in 0 .. len(branch) - 2:
-        if overlap(regs[ra].regToNode, branch.sons[j]):
+      for j in 0..<branch.len - 1:
+        if overlap(regs[ra].regToNode, branch[j]):
           cond = true
           break
       assert c.code[pc+1].opcode == opcFJmp
@@ -1241,7 +1241,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
           regs[ra].node
       c.currentExceptionA = raised
       # Set the `name` field of the exception
-      c.currentExceptionA.sons[2].skipColon.strVal = c.currentExceptionA.typ.sym.name.s
+      c.currentExceptionA[2].skipColon.strVal = c.currentExceptionA.typ.sym.name.s
       c.exceptionInstr = pc
 
       var frame = tos
@@ -1284,8 +1284,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       regs[ra].node = newNodeI(nkBracket, c.debug[pc])
       regs[ra].node.typ = typ
       newSeq(regs[ra].node.sons, count)
-      for i in 0 ..< count:
-        regs[ra].node.sons[i] = getNullValue(typ.sons[0], c.debug[pc], c.config)
+      for i in 0..<count:
+        regs[ra].node[i] = getNullValue(typ[0], c.debug[pc], c.config)
     of opcNewStr:
       decodeB(rkNode)
       regs[ra].node = newNodeI(nkStrLit, c.debug[pc])
@@ -1315,7 +1315,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         regs[ra].intVal = 0
     of opcLdConst:
       let rb = instr.regBx - wordExcess
-      let cnst = c.constants.sons[rb]
+      let cnst = c.constants[rb]
       if fitsRegister(cnst.typ):
         myreset(regs[ra])
         putIntoReg(regs[ra], cnst)
@@ -1324,7 +1324,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         regs[ra].node = cnst
     of opcAsgnConst:
       let rb = instr.regBx - wordExcess
-      let cnst = c.constants.sons[rb]
+      let cnst = c.constants[rb]
       if fitsRegister(cnst.typ):
         putIntoReg(regs[ra], cnst)
       else:
@@ -1333,11 +1333,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcLdGlobal:
       let rb = instr.regBx - wordExcess - 1
       ensureKind(rkNode)
-      regs[ra].node = c.globals.sons[rb]
+      regs[ra].node = c.globals[rb]
     of opcLdGlobalAddr:
       let rb = instr.regBx - wordExcess - 1
       ensureKind(rkNodeAddr)
-      regs[ra].nodeAddr = addr(c.globals.sons[rb])
+      regs[ra].nodeAddr = addr(c.globals[rb])
     of opcRepr:
       decodeB(rkNode)
       createStr regs[ra]
@@ -1391,15 +1391,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         # reference with the value `nil`, so `isNil` should be false!
         (node.kind == nkNilLit and nfIsRef notin node.flags) or
         (not node.typ.isNil and node.typ.kind == tyProc and
-          node.typ.callConv == ccClosure and node.sons[0].kind == nkNilLit and
-          node.sons[1].kind == nkNilLit))
+          node.typ.callConv == ccClosure and node[0].kind == nkNilLit and
+          node[1].kind == nkNilLit))
     of opcNBindSym:
       # cannot use this simple check
       # if dynamicBindSym notin c.config.features:
 
       # bindSym with static input
       decodeBx(rkNode)
-      regs[ra].node = copyTree(c.constants.sons[rbx])
+      regs[ra].node = copyTree(c.constants[rbx])
       regs[ra].node.flags.incl nfIsRef
     of opcNDynBindSym:
       # experimental bindSym
@@ -1422,7 +1422,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       elif idx >=% src.len:
         stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.len-1))
       else:
-        regs[ra].node = src.sons[idx]
+        regs[ra].node = src[idx]
     of opcNSetChild:
       decodeBC(rkNode)
       let idx = regs[rb].intVal.int
@@ -1434,7 +1434,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       elif idx >=% dest.len:
         stackTrace(c, tos, pc, formatErrorIndexBound(idx, dest.len-1))
       else:
-        dest.sons[idx] = regs[rc].node
+        dest[idx] = regs[rc].node
     of opcNAdd:
       decodeBC(rkNode)
       var u = regs[rb].node
@@ -1454,7 +1454,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       elif u.kind in {nkEmpty..nkNilLit}:
         stackTrace(c, tos, pc, "cannot add to node kind: n" & $u.kind)
       else:
-        for i in 0 ..< x.len: u.add(x.sons[i])
+        for i in 0..<x.len: u.add(x[i])
       regs[ra].node = u
     of opcNKind:
       decodeB(rkInt)
@@ -1629,11 +1629,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
                                 error = formatMsg(conf, info, msg, arg))
       if error.len > 0:
         c.errorFlag = error
-      elif len(ast) != 1:
+      elif ast.len != 1:
         c.errorFlag = formatMsg(c.config, c.debug[pc], errGenerated,
           "expected expression, but got multiple statements")
       else:
-        regs[ra].node = ast.sons[0]
+        regs[ra].node = ast[0]
     of opcParseStmtToAst:
       decodeB(rkNode)
       var error: string
@@ -1841,7 +1841,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcNDel:
       decodeBC(rkNode)
       let bb = regs[rb].intVal.int
-      for i in 0 ..< regs[rc].intVal.int:
+      for i in 0..<regs[rc].intVal.int:
         delSon(regs[ra].node, bb)
     of opcGenSym:
       decodeBC(rkNode)
@@ -1962,7 +1962,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       decodeB(rkNode)
       var typ = regs[rb].node.typ
       internalAssert c.config, typ != nil
-      while typ.kind == tyTypeDesc and typ.len > 0: typ = typ.sons[0]
+      while typ.kind == tyTypeDesc and typ.len > 0: typ = typ[0]
       createStr regs[ra]
       regs[ra].node.strVal = typ.typeToString(preferExported)
     of opcMarshalLoad:
@@ -2001,8 +2001,8 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
       newSeq(tos.slots, maxSlots)
 
       # setup parameters:
-      if not isEmptyType(sym.typ.sons[0]) or sym.kind == skMacro:
-        putIntoReg(tos.slots[0], getNullValue(sym.typ.sons[0], sym.info, c.config))
+      if not isEmptyType(sym.typ[0]) or sym.kind == skMacro:
+        putIntoReg(tos.slots[0], getNullValue(sym.typ[0], sym.info, c.config))
       # XXX We could perform some type checking here.
       for i in 1..<sym.typ.len:
         putIntoReg(tos.slots[i], args[i-1])
@@ -2028,7 +2028,7 @@ proc evalExpr*(c: PCtx, n: PNode): PNode =
 
 proc getGlobalValue*(c: PCtx; s: PSym): PNode =
   internalAssert c.config, s.kind in {skLet, skVar} and sfGlobal in s.flags
-  result = c.globals.sons[s.position-1]
+  result = c.globals[s.position-1]
 
 include vmops
 
@@ -2079,7 +2079,7 @@ proc evalConstExprAux(module: PSym;
   when debugEchoCode: c.echoCode start
   var tos = PStackFrame(prc: prc, comesFrom: 0, next: nil)
   newSeq(tos.slots, c.prc.maxSlots)
-  #for i in 0 ..< c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
+  #for i in 0..<c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
   result = rawExecute(c, start, tos).regToNode
   if result.info.col < 0: result.info = n.info
 
@@ -2121,7 +2121,7 @@ proc setupMacroParam(x: PNode, typ: PType): TFullReg =
   else:
     result.kind = rkNode
     var n = x
-    if n.kind in {nkHiddenSubConv, nkHiddenStdConv}: n = n.sons[1]
+    if n.kind in {nkHiddenSubConv, nkHiddenStdConv}: n = n[1]
     n = n.canonValue
     n.flags.incl nfIsRef
     n.typ = x.typ
@@ -2129,7 +2129,7 @@ proc setupMacroParam(x: PNode, typ: PType): TFullReg =
 
 iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) =
   let gp = macroSym.ast[genericParamsPos]
-  for i in 0 ..< gp.len:
+  for i in 0..<gp.len:
     let genericParam = gp[i].sym
     let posInCall = macroSym.typ.len + i
     if posInCall < call.len:
@@ -2182,20 +2182,20 @@ proc evalMacroCall*(module: PSym; g: ModuleGraph;
 
   # setup parameters:
   for i in 1..<sym.typ.len:
-    tos.slots[i] = setupMacroParam(n.sons[i], sym.typ.sons[i])
+    tos.slots[i] = setupMacroParam(n[i], sym.typ[i])
 
   let gp = sym.ast[genericParamsPos]
-  for i in 0 ..< gp.len:
+  for i in 0..<gp.len:
     let idx = sym.typ.len + i
     if idx < n.len:
-      tos.slots[idx] = setupMacroParam(n.sons[idx], gp[i].sym.typ)
+      tos.slots[idx] = setupMacroParam(n[idx], gp[i].sym.typ)
     else:
       dec(g.config.evalMacroCounter)
       c.callsite = nil
       localError(c.config, n.info, "expected " & $gp.len &
                  " generic parameter(s)")
   # temporary storage:
-  #for i in L ..< maxSlots: tos.slots[i] = newNode(nkEmpty)
+  #for i in L..<maxSlots: tos.slots[i] = newNode(nkEmpty)
   result = rawExecute(c, start, tos).regToNode
   if result.info.line < 0: result.info = n.info
   if cyclicTree(result): globalError(c.config, n.info, "macro produced a cyclic tree")
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index 06e309678..0ba4c2c78 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -21,7 +21,7 @@ const
 
 type
   TRegister* = range[0..255]
-  TDest* = range[-1 .. 255]
+  TDest* = range[-1..255]
   TInstr* = distinct uint32
 
   TOpcode* = enum
diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim
index 5be25ba1b..79d49698a 100644
--- a/compiler/vmdeps.nim
+++ b/compiler/vmdeps.nim
@@ -43,13 +43,13 @@ proc mapTypeToBracketX(cache: IdentCache; name: string; m: TMagic; t: PType; inf
                        inst=false): PNode =
   result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
   result.add atomicTypeX(cache, name, m, t, info)
-  for i in 0 ..< t.len:
-    if t.sons[i] == nil:
+  for i in 0..<t.len:
+    if t[i] == nil:
       let void = atomicTypeX(cache, "void", mVoid, t, info)
       void.typ = newType(tyVoid, t.owner)
       result.add void
     else:
-      result.add mapTypeToAstX(cache, t.sons[i], info, inst)
+      result.add mapTypeToAstX(cache, t[i], info, inst)
 
 proc objectNode(cache: IdentCache; n: PNode): PNode =
   if n.kind == nkSym:
@@ -59,7 +59,7 @@ proc objectNode(cache: IdentCache; n: PNode): PNode =
     result.add newNodeI(nkEmpty, n.info)  # no assigned value
   else:
     result = copyNode(n)
-    for i in 0 ..< n.safeLen:
+    for i in 0..<n.safeLen:
       result.add objectNode(cache, n[i])
 
 proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
@@ -70,7 +70,7 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
   template mapTypeToAst(t,info): untyped = mapTypeToAstX(cache, t, info, inst)
   template mapTypeToAstR(t,info): untyped = mapTypeToAstX(cache, t, info, inst, true)
   template mapTypeToAst(t,i,info): untyped =
-    if i<t.len and t.sons[i]!=nil: mapTypeToAstX(cache, t.sons[i], info, inst)
+    if i<t.len and t[i]!=nil: mapTypeToAstX(cache, t[i], info, inst)
     else: newNodeI(nkEmpty, info)
   template mapTypeToBracket(name, m, t, info): untyped =
     mapTypeToBracketX(cache, name, m, t, info, inst)
@@ -100,19 +100,19 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
   of tyUncheckedArray:
     result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
     result.add atomicType("UncheckedArray", mUncheckedArray)
-    result.add mapTypeToAst(t.sons[0], info)
+    result.add mapTypeToAst(t[0], info)
   of tyArray:
     result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
     result.add atomicType("array", mArray)
-    if inst and t.sons[0].kind == tyRange:
+    if inst and t[0].kind == tyRange:
       var rng = newNodeX(nkInfix)
       rng.add newIdentNode(getIdent(cache, ".."), info)
-      rng.add t.sons[0].n.sons[0].copyTree
-      rng.add t.sons[0].n.sons[1].copyTree
+      rng.add t[0].n[0].copyTree
+      rng.add t[0].n[1].copyTree
       result.add rng
     else:
-      result.add mapTypeToAst(t.sons[0], info)
-    result.add mapTypeToAst(t.sons[1], info)
+      result.add mapTypeToAst(t[0], info)
+    result.add mapTypeToAst(t[1], info)
   of tyTypeDesc:
     if t.base != nil:
       result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
@@ -122,8 +122,8 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
       result = atomicType("typeDesc", mTypeDesc)
   of tyGenericInvocation:
     result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
-    for i in 0 ..< t.len:
-      result.add mapTypeToAst(t.sons[i], info)
+    for i in 0..<t.len:
+      result.add mapTypeToAst(t[i], info)
   of tyGenericInst:
     if inst:
       if allowRecursion:
@@ -132,8 +132,8 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
         result = newNodeX(nkBracketExpr)
         #result.add mapTypeToAst(t.lastSon, info)
         result.add mapTypeToAst(t[0], info)
-        for i in 1 ..< t.len-1:
-          result.add mapTypeToAst(t.sons[i], info)
+        for i in 1..<t.len-1:
+          result.add mapTypeToAst(t[i], info)
     else:
       result = mapTypeToAstX(cache, t.lastSon, info, inst, allowRecursion)
   of tyGenericBody:
@@ -148,7 +148,7 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
   of tyDistinct:
     if inst:
       result = newNodeX(nkDistinctTy)
-      result.add mapTypeToAst(t.sons[0], info)
+      result.add mapTypeToAst(t[0], info)
     else:
       if allowRecursion or t.sym == nil:
         result = mapTypeToBracket("distinct", mDistinct, t, info)
@@ -163,11 +163,11 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
         result.add t.sym.ast[2][0].copyTree  # copy object pragmas
       else:
         result.add newNodeI(nkEmpty, info)
-      if t.sons[0] == nil:
+      if t[0] == nil:
         result.add newNodeI(nkEmpty, info)
       else:  # handle parent object
         var nn = newNodeX(nkOfInherit)
-        nn.add mapTypeToAst(t.sons[0], info)
+        nn.add mapTypeToAst(t[0], info)
         result.add nn
       if t.n.len > 0:
         result.add objectNode(cache, t.n)
@@ -177,10 +177,10 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
       if allowRecursion or t.sym == nil:
         result = newNodeIT(nkObjectTy, if t.n.isNil: info else: t.n.info, t)
         result.add newNodeI(nkEmpty, info)
-        if t.sons[0] == nil:
+        if t[0] == nil:
           result.add newNodeI(nkEmpty, info)
         else:
-          result.add mapTypeToAst(t.sons[0], info)
+          result.add mapTypeToAst(t[0], info)
         result.add copyTree(t.n)
       else:
         result = atomicType(t.sym)
@@ -206,19 +206,19 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
   of tyPtr:
     if inst:
       result = newNodeX(nkPtrTy)
-      result.add mapTypeToAst(t.sons[0], info)
+      result.add mapTypeToAst(t[0], info)
     else:
       result = mapTypeToBracket("ptr", mPtr, t, info)
   of tyRef:
     if inst:
       result = newNodeX(nkRefTy)
-      result.add mapTypeToAst(t.sons[0], info)
+      result.add mapTypeToAst(t[0], info)
     else:
       result = mapTypeToBracket("ref", mRef, t, info)
   of tyVar:
     if inst:
       result = newNodeX(nkVarTy)
-      result.add mapTypeToAst(t.sons[0], info)
+      result.add mapTypeToAst(t[0], info)
     else:
       result = mapTypeToBracket("var", mVar, t, info)
   of tyLent: result = mapTypeToBracket("lent", mBuiltinType, t, info)
@@ -229,12 +229,12 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
     if inst:
       result = newNodeX(nkProcTy)
       var fp = newNodeX(nkFormalParams)
-      if t.sons[0] == nil:
+      if t[0] == nil:
         fp.add newNodeI(nkEmpty, info)
       else:
-        fp.add mapTypeToAst(t.sons[0], t.n[0].info)
-      for i in 1..<t.sons.len:
-        fp.add newIdentDefs(t.n[i], t.sons[i])
+        fp.add mapTypeToAst(t[0], t.n[0].info)
+      for i in 1..<t.len:
+        fp.add newIdentDefs(t.n[i], t[i])
       result.add fp
       result.add if t.n[0].len > 0: t.n[0][pragmasEffects].copyTree
                  else: newNodeI(nkEmpty, info)
@@ -247,13 +247,13 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
     if inst and t.n.len == 2:
       let rng = newNodeX(nkInfix)
       rng.add newIdentNode(getIdent(cache, ".."), info)
-      rng.add t.n.sons[0].copyTree
-      rng.add t.n.sons[1].copyTree
+      rng.add t.n[0].copyTree
+      rng.add t.n[1].copyTree
       result.add rng
     else:
-      result.add t.n.sons[0].copyTree
+      result.add t.n[0].copyTree
       if t.n.len > 1:
-        result.add t.n.sons[1].copyTree
+        result.add t.n[1].copyTree
   of tyPointer: result = atomicType("pointer", mPointer)
   of tyString: result = atomicType("string", mString)
   of tyCString: result = atomicType("cstring", mCstring)
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 668c496c6..17e9f8de3 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -16,7 +16,7 @@
 #   types that use the 'node' field; the reason is that slots are
 #   re-used in a register based VM. Example:
 #
-# .. code-block:: nim
+#..code-block:: nim
 #   let s = a & b  # no matter what, create fresh node
 #   s = a & b  # no matter what, keep the node
 #
@@ -207,14 +207,14 @@ proc getFreeRegister(cc: PCtx; k: TSlotKind; start: int): TRegister =
   # we prefer the same slot kind here for efficiency. Unfortunately for
   # discardable return types we may not know the desired type. This can happen
   # for e.g. mNAdd[Multiple]:
-  for i in start .. c.maxSlots-1:
+  for i in start..c.maxSlots-1:
     if c.slots[i].kind == k and not c.slots[i].inUse:
       c.slots[i].inUse = true
       return TRegister(i)
 
   # if register pressure is high, we re-use more aggressively:
   if c.maxSlots >= high(TRegister):
-    for i in start .. c.maxSlots-1:
+    for i in start..c.maxSlots-1:
       if not c.slots[i].inUse:
         c.slots[i] = (inUse: true, kind: k)
         return TRegister(i)
@@ -248,22 +248,22 @@ proc getTempRange(cc: PCtx; n: int; kind: TSlotKind): TRegister =
   # if register pressure is high, we re-use more aggressively:
   let c = cc.prc
   if c.maxSlots >= HighRegisterPressure or c.maxSlots+n >= high(TRegister):
-    for i in 0 .. c.maxSlots-n:
+    for i in 0..c.maxSlots-n:
       if not c.slots[i].inUse:
         block search:
-          for j in i+1 .. i+n-1:
+          for j in i+1..i+n-1:
             if c.slots[j].inUse: break search
           result = TRegister(i)
-          for k in result .. result+n-1: c.slots[k] = (inUse: true, kind: kind)
+          for k in result..result+n-1: c.slots[k] = (inUse: true, kind: kind)
           return
   if c.maxSlots+n >= high(TRegister):
     globalError(cc.config, cc.bestEffort, "VM problem: too many registers required")
   result = TRegister(c.maxSlots)
   inc c.maxSlots, n
-  for k in result .. result+n-1: c.slots[k] = (inUse: true, kind: kind)
+  for k in result..result+n-1: c.slots[k] = (inUse: true, kind: kind)
 
 proc freeTempRange(c: PCtx; start: TRegister, n: int) =
-  for i in start .. start+n-1: c.freeTemp(TRegister(i))
+  for i in start..start+n-1: c.freeTemp(TRegister(i))
 
 template withTemp(tmp, typ, body: untyped) {.dirty.} =
   var tmp = getTemp(c, typ)
@@ -309,8 +309,8 @@ proc clearDest(c: PCtx; n: PNode; dest: var TDest) {.inline.} =
     dest = -1
 
 proc isNotOpr(n: PNode): bool =
-  n.kind in nkCallKinds and n.sons[0].kind == nkSym and
-    n.sons[0].sym.magic == mNot
+  n.kind in nkCallKinds and n[0].kind == nkSym and
+    n[0].sym.magic == mNot
 
 proc isTrue(n: PNode): bool =
   n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
@@ -325,30 +325,30 @@ proc genWhile(c: PCtx; n: PNode) =
   # lab2:
   let lab1 = c.genLabel
   withBlock(nil):
-    if isTrue(n.sons[0]):
-      c.gen(n.sons[1])
+    if isTrue(n[0]):
+      c.gen(n[1])
       c.jmpBack(n, lab1)
-    elif isNotOpr(n.sons[0]):
-      var tmp = c.genx(n.sons[0].sons[1])
+    elif isNotOpr(n[0]):
+      var tmp = c.genx(n[0][1])
       let lab2 = c.xjmp(n, opcTJmp, tmp)
       c.freeTemp(tmp)
-      c.gen(n.sons[1])
+      c.gen(n[1])
       c.jmpBack(n, lab1)
       c.patch(lab2)
     else:
-      var tmp = c.genx(n.sons[0])
+      var tmp = c.genx(n[0])
       let lab2 = c.xjmp(n, opcFJmp, tmp)
       c.freeTemp(tmp)
-      c.gen(n.sons[1])
+      c.gen(n[1])
       c.jmpBack(n, lab1)
       c.patch(lab2)
 
 proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
   let oldRegisterCount = c.prc.maxSlots
-  withBlock(n.sons[0].sym):
-    c.gen(n.sons[1], dest)
+  withBlock(n[0].sym):
+    c.gen(n[1], dest)
 
-  for i in oldRegisterCount ..< c.prc.maxSlots:
+  for i in oldRegisterCount..<c.prc.maxSlots:
     #if c.prc.slots[i].kind in {slotFixedVar, slotFixedLet}:
     if i != dest:
       when not defined(release):
@@ -364,10 +364,10 @@ proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
 
 proc genBreak(c: PCtx; n: PNode) =
   let lab1 = c.xjmp(n, opcJmp)
-  if n.sons[0].kind == nkSym:
-    #echo cast[int](n.sons[0].sym)
+  if n[0].kind == nkSym:
+    #echo cast[int](n[0].sym)
     for i in countdown(c.prc.blocks.len-1, 0):
-      if c.prc.blocks[i].label == n.sons[0].sym:
+      if c.prc.blocks[i].label == n[0].sym:
         c.prc.blocks[i].fixups.add lab1
         return
     globalError(c.config, n.info, "VM problem: cannot find 'break' target")
@@ -387,25 +387,25 @@ proc genIf(c: PCtx, n: PNode; dest: var TDest) =
   #  Lend:
   if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
   var endings: seq[TPosition] = @[]
-  for i in 0 ..< len(n):
-    var it = n.sons[i]
+  for i in 0..<n.len:
+    var it = n[i]
     if it.len == 2:
-      withTemp(tmp, it.sons[0].typ):
+      withTemp(tmp, it[0].typ):
         var elsePos: TPosition
-        if isNotOpr(it.sons[0]):
-          c.gen(it.sons[0].sons[1], tmp)
-          elsePos = c.xjmp(it.sons[0].sons[1], opcTJmp, tmp) # if true
+        if isNotOpr(it[0]):
+          c.gen(it[0][1], tmp)
+          elsePos = c.xjmp(it[0][1], opcTJmp, tmp) # if true
         else:
-          c.gen(it.sons[0], tmp)
-          elsePos = c.xjmp(it.sons[0], opcFJmp, tmp) # if false
+          c.gen(it[0], tmp)
+          elsePos = c.xjmp(it[0], opcFJmp, tmp) # if false
       c.clearDest(n, dest)
-      c.gen(it.sons[1], dest) # then part
-      if i < len(n)-1:
-        endings.add(c.xjmp(it.sons[1], opcJmp, 0))
+      c.gen(it[1], dest) # then part
+      if i < n.len-1:
+        endings.add(c.xjmp(it[1], opcJmp, 0))
       c.patch(elsePos)
     else:
       c.clearDest(n, dest)
-      c.gen(it.sons[0], dest)
+      c.gen(it[0], dest)
   for endPos in endings: c.patch(endPos)
   c.clearDest(n, dest)
 
@@ -422,9 +422,9 @@ proc genAndOr(c: PCtx; n: PNode; opc: TOpcode; dest: var TDest) =
               getTemp(c, n.typ)
             else:
               TRegister dest
-  c.gen(n.sons[1], tmp)
+  c.gen(n[1], tmp)
   let lab1 = c.xjmp(n, opc, tmp)
-  c.gen(n.sons[2], tmp)
+  c.gen(n[2], tmp)
   c.patch(lab1)
   if dest < 0:
     dest = tmp
@@ -456,14 +456,14 @@ proc sameConstant*(a, b: PNode): bool =
     of nkType, nkNilLit: result = a.typ == b.typ
     of nkEmpty: result = true
     else:
-      if len(a) == len(b):
-        for i in 0 ..< len(a):
-          if not sameConstant(a.sons[i], b.sons[i]): return
+      if a.len == b.len:
+        for i in 0..<a.len:
+          if not sameConstant(a[i], b[i]): return
         result = true
 
 proc genLiteral(c: PCtx; n: PNode): int =
   # types do not matter here:
-  for i in 0 ..< c.constants.len:
+  for i in 0..<c.constants.len:
     if sameConstant(c.constants[i], n): return i
   result = rawGenLiteral(c, n)
 
@@ -488,21 +488,21 @@ proc genCase(c: PCtx; n: PNode; dest: var TDest) =
   else:
     unused(c, n, dest)
   var endings: seq[TPosition] = @[]
-  withTemp(tmp, n.sons[0].typ):
-    c.gen(n.sons[0], tmp)
+  withTemp(tmp, n[0].typ):
+    c.gen(n[0], tmp)
     # branch tmp, codeIdx
     # fjmp   elseLabel
-    for i in 1 ..< n.len:
-      let it = n.sons[i]
+    for i in 1..<n.len:
+      let it = n[i]
       if it.len == 1:
         # else stmt:
-        c.gen(it.sons[0], dest)
+        c.gen(it[0], dest)
       else:
         let b = rawGenLiteral(c, it)
         c.gABx(it, opcBranch, tmp, b)
         let elsePos = c.xjmp(it.lastSon, opcFJmp, tmp)
         c.gen(it.lastSon, dest)
-        if i < len(n)-1:
+        if i < n.len-1:
           endings.add(c.xjmp(it.lastSon, opcJmp, 0))
         c.patch(elsePos)
       c.clearDest(n, dest)
@@ -519,28 +519,27 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
   if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
   var endings: seq[TPosition] = @[]
   let ehPos = c.xjmp(n, opcTry, 0)
-  c.gen(n.sons[0], dest)
+  c.gen(n[0], dest)
   c.clearDest(n, dest)
   # Add a jump past the exception handling code
   let jumpToFinally = c.xjmp(n, opcJmp, 0)
   # This signals where the body ends and where the exception handling begins
   c.patch(ehPos)
-  for i in 1 ..< n.len:
-    let it = n.sons[i]
+  for i in 1..<n.len:
+    let it = n[i]
     if it.kind != nkFinally:
-      var blen = len(it)
       # first opcExcept contains the end label of the 'except' block:
       let endExcept = c.xjmp(it, opcExcept, 0)
-      for j in 0 .. blen - 2:
-        assert(it.sons[j].kind == nkType)
-        let typ = it.sons[j].typ.skipTypes(abstractPtrs-{tyTypeDesc})
+      for j in 0..<it.len - 1:
+        assert(it[j].kind == nkType)
+        let typ = it[j].typ.skipTypes(abstractPtrs-{tyTypeDesc})
         c.gABx(it, opcExcept, 0, c.genType(typ))
-      if blen == 1:
+      if it.len == 1:
         # general except section:
         c.gABx(it, opcExcept, 0, 0)
       c.gen(it.lastSon, dest)
       c.clearDest(n, dest)
-      if i < len(n):
+      if i < n.len:
         endings.add(c.xjmp(it, opcJmp, 0))
       c.patch(endExcept)
   let fin = lastSon(n)
@@ -550,18 +549,18 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
   c.gABx(fin, opcFinally, 0, 0)
   for endPos in endings: c.patch(endPos)
   if fin.kind == nkFinally:
-    c.gen(fin.sons[0])
+    c.gen(fin[0])
     c.clearDest(n, dest)
   c.gABx(fin, opcFinallyEnd, 0, 0)
 
 proc genRaise(c: PCtx; n: PNode) =
-  let dest = genx(c, n.sons[0])
+  let dest = genx(c, n[0])
   c.gABC(n, opcRaise, dest)
   c.freeTemp(dest)
 
 proc genReturn(c: PCtx; n: PNode) =
-  if n.sons[0].kind != nkEmpty:
-    gen(c, n.sons[0])
+  if n[0].kind != nkEmpty:
+    gen(c, n[0])
   c.gABC(n, opcRet)
 
 
@@ -585,16 +584,16 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) =
   if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
   let x = c.getTempRange(n.len, slotTempUnknown)
   # varargs need 'opcSetType' for the FFI support:
-  let fntyp = skipTypes(n.sons[0].typ, abstractInst)
+  let fntyp = skipTypes(n[0].typ, abstractInst)
   for i in 0..<n.len:
-    #if i > 0 and i < len(fntyp):
-    #  let paramType = fntyp.n.sons[i]
+    #if i > 0 and i < fntyp.len:
+    #  let paramType = fntyp.n[i]
     #  if paramType.typ.isCompileTimeOnly: continue
     var r: TRegister = x+i
-    c.gen(n.sons[i], r, {gfIsParam})
+    c.gen(n[i], r, {gfIsParam})
     if i >= fntyp.len:
       internalAssert c.config, tfVarargs in fntyp.flags
-      c.gABx(n, opcSetType, r, c.genType(n.sons[i].typ))
+      c.gABx(n, opcSetType, r, c.genType(n[i].typ))
   if dest < 0:
     c.gABC(n, opcIndCall, 0, x, n.len)
   else:
@@ -633,24 +632,24 @@ proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags
 proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
   case le.kind
   of nkBracketExpr:
-    let dest = c.genx(le.sons[0], {gfNode})
-    let idx = c.genIndex(le.sons[1], le.sons[0].typ)
+    let dest = c.genx(le[0], {gfNode})
+    let idx = c.genIndex(le[1], le[0].typ)
     c.gABC(le, opcWrArr, dest, idx, value)
     c.freeTemp(dest)
     c.freeTemp(idx)
   of nkCheckedFieldExpr:
     var objR: TDest = -1
     genCheckedObjAccessAux(c, le, objR, {gfNode})
-    let idx = genField(c, le[0].sons[1])
+    let idx = genField(c, le[0][1])
     c.gABC(le[0], opcWrObj, objR, idx, value)
     c.freeTemp(objR)
   of nkDotExpr:
-    let dest = c.genx(le.sons[0], {gfNode})
-    let idx = genField(c, le.sons[1])
+    let dest = c.genx(le[0], {gfNode})
+    let idx = genField(c, le[1])
     c.gABC(le, opcWrObj, dest, idx, value)
     c.freeTemp(dest)
   of nkDerefExpr, nkHiddenDeref:
-    let dest = c.genx(le.sons[0], {gfNode})
+    let dest = c.genx(le[0], {gfNode})
     c.gABC(le, opcWrDeref, dest, 0, value)
     c.freeTemp(dest)
   of nkSym:
@@ -662,30 +661,30 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
     discard
 
 proc genNew(c: PCtx; n: PNode) =
-  let dest = if needsAsgnPatch(n.sons[1]): c.getTemp(n.sons[1].typ)
-             else: c.genx(n.sons[1])
+  let dest = if needsAsgnPatch(n[1]): c.getTemp(n[1].typ)
+             else: c.genx(n[1])
   # we use the ref's base type here as the VM conflates 'ref object'
   # and 'object' since internally we already have a pointer.
   c.gABx(n, opcNew, dest,
-         c.genType(n.sons[1].typ.skipTypes(abstractVar-{tyTypeDesc}).sons[0]))
-  c.genAsgnPatch(n.sons[1], dest)
+         c.genType(n[1].typ.skipTypes(abstractVar-{tyTypeDesc})[0]))
+  c.genAsgnPatch(n[1], dest)
   c.freeTemp(dest)
 
 proc genNewSeq(c: PCtx; n: PNode) =
-  let t = n.sons[1].typ
-  let dest = if needsAsgnPatch(n.sons[1]): c.getTemp(t)
-             else: c.genx(n.sons[1])
-  let tmp = c.genx(n.sons[2])
+  let t = n[1].typ
+  let dest = if needsAsgnPatch(n[1]): c.getTemp(t)
+             else: c.genx(n[1])
+  let tmp = c.genx(n[2])
   c.gABx(n, opcNewSeq, dest, c.genType(t.skipTypes(
                                                   abstractVar-{tyTypeDesc})))
   c.gABx(n, opcNewSeq, tmp, 0)
   c.freeTemp(tmp)
-  c.genAsgnPatch(n.sons[1], dest)
+  c.genAsgnPatch(n[1], dest)
   c.freeTemp(dest)
 
 proc genNewSeqOfCap(c: PCtx; n: PNode; dest: var TDest) =
   let t = n.typ
-  let tmp = c.getTemp(n.sons[1].typ)
+  let tmp = c.getTemp(n[1].typ)
   c.gABx(n, opcLdNull, dest, c.genType(t))
   c.gABx(n, opcLdImmInt, tmp, 0)
   c.gABx(n, opcNewSeq, dest, c.genType(t.skipTypes(
@@ -694,13 +693,13 @@ proc genNewSeqOfCap(c: PCtx; n: PNode; dest: var TDest) =
   c.freeTemp(tmp)
 
 proc genUnaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
-  let tmp = c.genx(n.sons[1])
+  let tmp = c.genx(n[1])
   if dest < 0: dest = c.getTemp(n.typ)
   c.gABC(n, opc, dest, tmp)
   c.freeTemp(tmp)
 
 proc genUnaryABI(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; imm: BiggestInt=0) =
-  let tmp = c.genx(n.sons[1])
+  let tmp = c.genx(n[1])
   if dest < 0: dest = c.getTemp(n.typ)
   c.gABI(n, opc, dest, tmp, imm)
   c.freeTemp(tmp)
@@ -708,8 +707,8 @@ proc genUnaryABI(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; imm: BiggestI
 
 proc genBinaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
   let
-    tmp = c.genx(n.sons[1])
-    tmp2 = c.genx(n.sons[2])
+    tmp = c.genx(n[1])
+    tmp2 = c.genx(n[2])
   if dest < 0: dest = c.getTemp(n.typ)
   c.gABC(n, opc, dest, tmp, tmp2)
   c.freeTemp(tmp)
@@ -717,9 +716,9 @@ proc genBinaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
 
 proc genBinaryABCD(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
   let
-    tmp = c.genx(n.sons[1])
-    tmp2 = c.genx(n.sons[2])
-    tmp3 = c.genx(n.sons[3])
+    tmp = c.genx(n[1])
+    tmp2 = c.genx(n[2])
+    tmp3 = c.genx(n[3])
   if dest < 0: dest = c.getTemp(n.typ)
   c.gABC(n, opc, dest, tmp, tmp2)
   c.gABC(n, opc, tmp3)
@@ -759,45 +758,45 @@ proc genSetType(c: PCtx; n: PNode; dest: TRegister) =
 
 proc genBinarySet(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
   let
-    tmp = c.genx(n.sons[1])
-    tmp2 = c.genx(n.sons[2])
+    tmp = c.genx(n[1])
+    tmp2 = c.genx(n[2])
   if dest < 0: dest = c.getTemp(n.typ)
-  c.genSetType(n.sons[1], tmp)
-  c.genSetType(n.sons[2], tmp2)
+  c.genSetType(n[1], tmp)
+  c.genSetType(n[2], tmp2)
   c.gABC(n, opc, dest, tmp, tmp2)
   c.freeTemp(tmp)
   c.freeTemp(tmp2)
 
 proc genBinaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
   let
-    dest = c.genx(n.sons[1])
-    tmp = c.genx(n.sons[2])
+    dest = c.genx(n[1])
+    tmp = c.genx(n[2])
   c.gABC(n, opc, dest, tmp, 0)
   c.freeTemp(tmp)
   c.freeTemp(dest)
 
 proc genBinaryStmtVar(c: PCtx; n: PNode; opc: TOpcode) =
-  var x = n.sons[1]
-  if x.kind in {nkAddr, nkHiddenAddr}: x = x.sons[0]
+  var x = n[1]
+  if x.kind in {nkAddr, nkHiddenAddr}: x = x[0]
   let
     dest = c.genx(x)
-    tmp = c.genx(n.sons[2])
+    tmp = c.genx(n[2])
   c.gABC(n, opc, dest, tmp, 0)
-  #c.genAsgnPatch(n.sons[1], dest)
+  #c.genAsgnPatch(n[1], dest)
   c.freeTemp(tmp)
   c.freeTemp(dest)
 
 proc genUnaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
-  let tmp = c.genx(n.sons[1])
+  let tmp = c.genx(n[1])
   c.gABC(n, opc, tmp, 0, 0)
   c.freeTemp(tmp)
 
 proc genVarargsABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
   if dest < 0: dest = getTemp(c, n.typ)
   var x = c.getTempRange(n.len-1, slotTempStr)
-  for i in 1..n.len-1:
+  for i in 1..<n.len:
     var r: TRegister = x+i-1
-    c.gen(n.sons[i], r)
+    c.gen(n[i], r)
   c.gABC(n, opc, dest, x, n.len-1)
   c.freeTempRange(x, n.len)
 
@@ -810,10 +809,10 @@ proc isInt16Lit(n: PNode): bool =
     result = n.intVal >= low(int16) and n.intVal <= high(int16)
 
 proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
-  if n.sons[2].isInt8Lit:
-    let tmp = c.genx(n.sons[1])
+  if n[2].isInt8Lit:
+    let tmp = c.genx(n[1])
     if dest < 0: dest = c.getTemp(n.typ)
-    c.gABI(n, succ(opc), dest, tmp, n.sons[2].intVal)
+    c.gABI(n, succ(opc), dest, tmp, n[2].intVal)
     c.freeTemp(tmp)
   else:
     genBinaryABC(c, n, dest, opc)
@@ -832,9 +831,9 @@ proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
   c.freeTemp(tmp)
 
 proc genCard(c: PCtx; n: PNode; dest: var TDest) =
-  let tmp = c.genx(n.sons[1])
+  let tmp = c.genx(n[1])
   if dest < 0: dest = c.getTemp(n.typ)
-  c.genSetType(n.sons[1], tmp)
+  c.genSetType(n[1], tmp)
   c.gABC(n, opcCard, dest, tmp)
   c.freeTemp(tmp)
 
@@ -842,12 +841,12 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
   const allowedIntegers = {tyInt..tyInt64, tyUInt..tyUInt64, tyChar}
   var signedIntegers = {tyInt..tyInt64}
   var unsignedIntegers = {tyUInt..tyUInt64, tyChar}
-  let src = n.sons[1].typ.skipTypes(abstractRange)#.kind
-  let dst = n.sons[0].typ.skipTypes(abstractRange)#.kind
+  let src = n[1].typ.skipTypes(abstractRange)#.kind
+  let dst = n[0].typ.skipTypes(abstractRange)#.kind
   let srcSize = getSize(c.config, src)
   let dstSize = getSize(c.config, dst)
   if src.kind in allowedIntegers and dst.kind in allowedIntegers:
-    let tmp = c.genx(n.sons[1])
+    let tmp = c.genx(n[1])
     if dest < 0: dest = c.getTemp(n[0].typ)
     c.gABC(n, opcAsgnInt, dest, tmp)
     if dstSize != sizeof(BiggestInt): # don't do anything on biggest int types
@@ -919,20 +918,20 @@ proc genBindSym(c: PCtx; n: PNode; dest: var TDest) =
 
     # callee symbol
     var tmp0 = TDest(x)
-    c.genLit(n.sons[0], tmp0)
+    c.genLit(n[0], tmp0)
 
     # original parameters
     for i in 1..<n.len-2:
       var r = TRegister(x+i)
-      c.gen(n.sons[i], r)
+      c.gen(n[i], r)
 
     # info node
     var tmp1 = TDest(x+n.len-2)
-    c.genLit(n.sons[^2], tmp1)
+    c.genLit(n[^2], tmp1)
 
     # payload idx
     var tmp2 = TDest(x+n.len-1)
-    c.genLit(n.sons[^1], tmp2)
+    c.genLit(n[^1], tmp2)
 
     c.gABC(n, opcNDynBindSym, dest, x, n.len)
     c.freeTempRange(x, n.len)
@@ -962,7 +961,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mAnd: c.genAndOr(n, opcFJmp, dest)
   of mOr:  c.genAndOr(n, opcTJmp, dest)
   of mUnaryLt:
-    let tmp = c.genx(n.sons[1])
+    let tmp = c.genx(n[1])
     if dest < 0: dest = c.getTemp(n.typ)
     c.gABI(n, opcSubImmInt, dest, tmp, 1)
     c.freeTemp(tmp)
@@ -972,22 +971,22 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     c.genAddSubInt(n, dest, opcAddInt)
   of mInc, mDec:
     unused(c, n, dest)
-    let isUnsigned = n.sons[1].typ.skipTypes(abstractVarRange).kind in {tyUInt..tyUInt64}
+    let isUnsigned = n[1].typ.skipTypes(abstractVarRange).kind in {tyUInt..tyUInt64}
     let opc = if not isUnsigned:
                 if m == mInc: opcAddInt else: opcSubInt
               else:
                 if m == mInc: opcAddu else: opcSubu
-    let d = c.genx(n.sons[1])
-    if n.sons[2].isInt8Lit and not isUnsigned:
-      c.gABI(n, succ(opc), d, d, n.sons[2].intVal)
+    let d = c.genx(n[1])
+    if n[2].isInt8Lit and not isUnsigned:
+      c.gABI(n, succ(opc), d, d, n[2].intVal)
     else:
-      let tmp = c.genx(n.sons[2])
+      let tmp = c.genx(n[2])
       c.gABC(n, opc, d, d, tmp)
       c.freeTemp(tmp)
-    c.genNarrow(n.sons[1], d)
-    c.genAsgnPatch(n.sons[1], d)
+    c.genNarrow(n[1], d)
+    c.genAsgnPatch(n[1], d)
     c.freeTemp(d)
-  of mOrd, mChr, mArrToSeq, mUnown: c.gen(n.sons[1], dest)
+  of mOrd, mChr, mArrToSeq, mUnown: c.gen(n[1], dest)
   of mNew, mNewFinalize:
     unused(c, n, dest)
     c.genNew(n)
@@ -1000,9 +999,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     # XXX buggy
   of mNewStringOfCap:
     # we ignore the 'cap' argument and translate it as 'newString(0)'.
-    # eval n.sons[1] for possible side effects:
-    c.freeTemp(c.genx(n.sons[1]))
-    var tmp = c.getTemp(n.sons[1].typ)
+    # eval n[1] for possible side effects:
+    c.freeTemp(c.genx(n[1]))
+    var tmp = c.getTemp(n[1].typ)
     c.gABx(n, opcLdImmInt, tmp, 0)
     if dest < 0: dest = c.getTemp(n.typ)
     c.gABC(n, opcNewStr, dest, tmp)
@@ -1014,9 +1013,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     genUnaryABI(c, n, dest, opcLenStr)
   of mIncl, mExcl:
     unused(c, n, dest)
-    var d = c.genx(n.sons[1])
-    var tmp = c.genx(n.sons[2])
-    c.genSetType(n.sons[1], d)
+    var d = c.genx(n[1])
+    var tmp = c.genx(n[2])
+    c.genSetType(n[1], d)
     c.gABC(n, if m == mIncl: opcIncl else: opcExcl, d, tmp)
     c.freeTemp(d)
     c.freeTemp(tmp)
@@ -1031,9 +1030,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mShrI:
     # modified: genBinaryABC(c, n, dest, opcShrInt)
     # narrowU is applied to the left operandthe idea here is to narrow the left operand
-    let tmp = c.genx(n.sons[1])
+    let tmp = c.genx(n[1])
     c.genNarrowU(n, tmp)
-    let tmp2 = c.genx(n.sons[2])
+    let tmp2 = c.genx(n[2])
     if dest < 0: dest = c.getTemp(n.typ)
     c.gABC(n, opcShrInt, dest, tmp, tmp2)
     c.freeTemp(tmp)
@@ -1074,7 +1073,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     genUnaryABC(c, n, dest, opcUnaryMinusInt)
     genNarrow(c, n, dest)
   of mUnaryMinusF64: genUnaryABC(c, n, dest, opcUnaryMinusFloat)
-  of mUnaryPlusI, mUnaryPlusF64: gen(c, n.sons[1], dest)
+  of mUnaryPlusI, mUnaryPlusF64: gen(c, n[1], dest)
   of mBitnotI:
     genUnaryABC(c, n, dest, opcBitnotInt)
     #genNarrowU modified, do not narrow signed types
@@ -1083,7 +1082,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
       c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
   of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr,
      mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
-    genConv(c, n, n.sons[1], dest)
+    genConv(c, n, n[1], dest)
   of mEqStr, mEqCString: genBinaryABC(c, n, dest, opcEqStr)
   of mLeStr: genBinaryABC(c, n, dest, opcLeStr)
   of mLtStr: genBinaryABC(c, n, dest, opcLtStr)
@@ -1099,15 +1098,15 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mRepr: genUnaryABC(c, n, dest, opcRepr)
   of mExit:
     unused(c, n, dest)
-    var tmp = c.genx(n.sons[1])
+    var tmp = c.genx(n[1])
     c.gABC(n, opcQuit, tmp)
     c.freeTemp(tmp)
   of mSetLengthStr, mSetLengthSeq:
     unused(c, n, dest)
-    var d = c.genx(n.sons[1])
-    var tmp = c.genx(n.sons[2])
+    var d = c.genx(n[1])
+    var tmp = c.genx(n[2])
     c.gABC(n, if m == mSetLengthStr: opcSetLenStr else: opcSetLenSeq, d, tmp)
-    c.genAsgnPatch(n.sons[1], d)
+    c.genAsgnPatch(n[1], d)
     c.freeTemp(tmp)
     c.freeTemp(d)
   of mSwap:
@@ -1117,9 +1116,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mCopyStr:
     if dest < 0: dest = c.getTemp(n.typ)
     var
-      tmp1 = c.genx(n.sons[1])
-      tmp2 = c.genx(n.sons[2])
-      tmp3 = c.getTemp(n.sons[2].typ)
+      tmp1 = c.genx(n[1])
+      tmp2 = c.genx(n[2])
+      tmp3 = c.getTemp(n[2].typ)
     c.gABC(n, opcLenStr, tmp3, tmp1)
     c.gABC(n, opcSubStr, dest, tmp1, tmp2)
     c.gABC(n, opcSubStr, tmp3)
@@ -1129,9 +1128,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mCopyStrLast:
     if dest < 0: dest = c.getTemp(n.typ)
     var
-      tmp1 = c.genx(n.sons[1])
-      tmp2 = c.genx(n.sons[2])
-      tmp3 = c.genx(n.sons[3])
+      tmp1 = c.genx(n[1])
+      tmp2 = c.genx(n[2])
+      tmp3 = c.genx(n[3])
     c.gABC(n, opcSubStr, dest, tmp1, tmp2)
     c.gABC(n, opcSubStr, tmp3)
     c.freeTemp(tmp1)
@@ -1141,14 +1140,14 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     if dest < 0: dest = c.getTemp(n.typ)
     var d2: TRegister
     # skip 'nkHiddenAddr':
-    let d2AsNode = n.sons[2].sons[0]
+    let d2AsNode = n[2][0]
     if needsAsgnPatch(d2AsNode):
       d2 = c.getTemp(getSysType(c.graph, n.info, tyFloat))
     else:
       d2 = c.genx(d2AsNode)
     var
-      tmp1 = c.genx(n.sons[1])
-      tmp3 = c.genx(n.sons[3])
+      tmp1 = c.genx(n[1])
+      tmp3 = c.genx(n[3])
     c.gABC(n, opcParseFloat, dest, tmp1, d2)
     c.gABC(n, opcParseFloat, tmp3)
     c.freeTemp(tmp1)
@@ -1157,19 +1156,19 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     c.freeTemp(d2)
   of mReset:
     unused(c, n, dest)
-    var d = c.genx(n.sons[1])
+    var d = c.genx(n[1])
     # XXX use ldNullOpcode() here?
-    c.gABx(n, opcLdNull, d, c.genType(n.sons[1].typ))
+    c.gABx(n, opcLdNull, d, c.genType(n[1].typ))
     c.gABx(n, opcNodeToReg, d, d)
-    c.genAsgnPatch(n.sons[1], d)
+    c.genAsgnPatch(n[1], d)
   of mDefault:
     if dest < 0: dest = c.getTemp(n.typ)
     c.gABx(n, ldNullOpcode(n.typ), dest, c.genType(n.typ))
   of mOf, mIs:
     if dest < 0: dest = c.getTemp(n.typ)
-    var tmp = c.genx(n.sons[1])
+    var tmp = c.genx(n[1])
     var idx = c.getTemp(getSysType(c.graph, n.info, tyInt))
-    var typ = n.sons[2].typ
+    var typ = n[2].typ
     if m == mOf: typ = typ.skipTypes(abstractPtrs)
     c.gABx(n, opcLdImmInt, idx, c.genType(typ))
     c.gABC(n, if m == mOf: opcOf else: opcIs, dest, tmp, idx)
@@ -1177,8 +1176,8 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     c.freeTemp(idx)
   of mHigh:
     if dest < 0: dest = c.getTemp(n.typ)
-    let tmp = c.genx(n.sons[1])
-    case n.sons[1].typ.skipTypes(abstractVar-{tyTypeDesc}).kind:
+    let tmp = c.genx(n[1])
+    case n[1].typ.skipTypes(abstractVar-{tyTypeDesc}).kind:
     of tyString, tyCString:
       c.gABI(n, opcLenStr, dest, tmp, 1)
     else:
@@ -1192,7 +1191,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
       let x = c.getTempRange(n.len, slotTempUnknown)
       for i in 0..<n.len:
         var r: TRegister = x+i
-        c.gen(n.sons[i], r)
+        c.gen(n[i], r)
       c.gABC(n, opcEcho, x, n.len)
       c.freeTempRange(x, n.len)
   of mAppendStrCh:
@@ -1209,9 +1208,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mParseStmtToAst:
     genUnaryABC(c, n, dest, opcParseStmtToAst)
   of mTypeTrait:
-    let tmp = c.genx(n.sons[1])
+    let tmp = c.genx(n[1])
     if dest < 0: dest = c.getTemp(n.typ)
-    c.gABx(n, opcSetType, tmp, c.genType(n.sons[1].typ))
+    c.gABx(n, opcSetType, tmp, c.genType(n[1].typ))
     c.gABC(n, opcTypeTrait, dest, tmp)
     c.freeTemp(tmp)
   of mSlurp: genUnaryABC(c, n, dest, opcSlurp)
@@ -1246,7 +1245,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mNSymbol: genUnaryABC(c, n, dest, opcNSymbol)
   of mNIdent: genUnaryABC(c, n, dest, opcNIdent)
   of mNGetType:
-    let tmp = c.genx(n.sons[1])
+    let tmp = c.genx(n[1])
     if dest < 0: dest = c.getTemp(n.typ)
     let rc = case n[0].sym.name.s:
       of "getType": 0
@@ -1323,7 +1322,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mExpandToAst:
     if n.len != 2:
       globalError(c.config, n.info, "expandToAst requires 1 argument")
-    let arg = n.sons[1]
+    let arg = n[1]
     if arg.kind in nkCallKinds:
       #if arg[0].kind != nkSym or arg[0].sym.kind notin {skTemplate, skMacro}:
       #      "ExpandToAst: expanded symbol is no macro or template"
@@ -1361,7 +1360,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
 proc genMarshalLoad(c: PCtx, n: PNode, dest: var TDest) =
   ## Signature: proc to*[T](data: string): T
   if dest < 0: dest = c.getTemp(n.typ)
-  var tmp = c.genx(n.sons[1])
+  var tmp = c.genx(n[1])
   c.gABC(n, opcMarshalLoad, dest, tmp)
   c.gABx(n, opcMarshalLoad, 0, c.genType(n.typ))
   c.freeTemp(tmp)
@@ -1369,9 +1368,9 @@ proc genMarshalLoad(c: PCtx, n: PNode, dest: var TDest) =
 proc genMarshalStore(c: PCtx, n: PNode, dest: var TDest) =
   ## Signature: proc `$$`*[T](x: T): string
   if dest < 0: dest = c.getTemp(n.typ)
-  var tmp = c.genx(n.sons[1])
+  var tmp = c.genx(n[1])
   c.gABC(n, opcMarshalStore, dest, tmp)
-  c.gABx(n, opcMarshalStore, 0, c.genType(n.sons[1].typ))
+  c.gABx(n, opcMarshalStore, 0, c.genType(n[1].typ))
   c.freeTemp(tmp)
 
 const
@@ -1391,26 +1390,26 @@ proc unneededIndirection(n: PNode): bool =
   n.typ.skipTypes(abstractInstOwned-{tyTypeDesc}).kind == tyRef
 
 proc canElimAddr(n: PNode): PNode =
-  if n.sons[0].typ.skipTypes(abstractInst).kind in {tyObject, tyTuple, tyArray}:
+  if n[0].typ.skipTypes(abstractInst).kind in {tyObject, tyTuple, tyArray}:
     # objects are reference types in the VM
     return n[0]
-  case n.sons[0].kind
+  case n[0].kind
   of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
-    var m = n.sons[0].sons[0]
+    var m = n[0][0]
     if m.kind in {nkDerefExpr, nkHiddenDeref}:
       # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
-      result = copyNode(n.sons[0])
-      result.add m.sons[0]
+      result = copyNode(n[0])
+      result.add m[0]
   of nkHiddenStdConv, nkHiddenSubConv, nkConv:
-    var m = n.sons[0].sons[1]
+    var m = n[0][1]
     if m.kind in {nkDerefExpr, nkHiddenDeref}:
       # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
-      result = copyNode(n.sons[0])
-      result.add m.sons[0]
+      result = copyNode(n[0])
+      result.add m[0]
   else:
-    if n.sons[0].kind in {nkDerefExpr, nkHiddenDeref}:
+    if n[0].kind in {nkDerefExpr, nkHiddenDeref}:
       # addr ( deref ( x )) --> x
-      result = n.sons[0].sons[0]
+      result = n[0][0]
 
 proc genAddr(c: PCtx, n: PNode, dest: var TDest, flags: TGenFlags) =
   if (let m = canElimAddr(n); m != nil):
@@ -1419,11 +1418,11 @@ proc genAddr(c: PCtx, n: PNode, dest: var TDest, flags: TGenFlags) =
 
   let newflags = flags-{gfNode}+{gfNodeAddr}
 
-  if isGlobal(n.sons[0]) or n[0].kind in {nkDotExpr, nkCheckedFieldExpr, nkBracketExpr}:
+  if isGlobal(n[0]) or n[0].kind in {nkDotExpr, nkCheckedFieldExpr, nkBracketExpr}:
     # checking for this pattern:  addr(obj.field) / addr(array[i])
-    gen(c, n.sons[0], dest, newflags)
+    gen(c, n[0], dest, newflags)
   else:
-    let tmp = c.genx(n.sons[0], newflags)
+    let tmp = c.genx(n[0], newflags)
     if dest < 0: dest = c.getTemp(n.typ)
     if c.prc.slots[tmp].kind >= slotTempUnknown:
       gABC(c, n, opcAddrNode, dest, tmp)
@@ -1437,12 +1436,12 @@ proc genAddr(c: PCtx, n: PNode, dest: var TDest, flags: TGenFlags) =
     c.freeTemp(tmp)
 
 proc genDeref(c: PCtx, n: PNode, dest: var TDest, flags: TGenFlags) =
-  if unneededIndirection(n.sons[0]):
-    gen(c, n.sons[0], dest, flags)
+  if unneededIndirection(n[0]):
+    gen(c, n[0], dest, flags)
     if {gfNodeAddr, gfNode} * flags == {} and fitsRegister(n.typ):
       c.gABC(n, opcNodeToReg, dest, dest)
   else:
-    let tmp = c.genx(n.sons[0], flags)
+    let tmp = c.genx(n[0], flags)
     if dest < 0: dest = c.getTemp(n.typ)
     gABC(c, n, opcLdDeref, dest, tmp)
     assert n.typ != nil
@@ -1514,10 +1513,10 @@ proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode;
 proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
   case le.kind
   of nkBracketExpr:
-    let dest = c.genx(le.sons[0], {gfNode})
-    let idx = c.genIndex(le.sons[1], le.sons[0].typ)
+    let dest = c.genx(le[0], {gfNode})
+    let idx = c.genIndex(le[1], le[0].typ)
     let tmp = c.genx(ri)
-    if le.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in {
+    if le[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in {
         tyString, tyCString}:
       c.preventFalseAlias(le, opcWrStrIdx, dest, idx, tmp)
     else:
@@ -1528,22 +1527,22 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
   of nkCheckedFieldExpr:
     var objR: TDest = -1
     genCheckedObjAccessAux(c, le, objR, {gfNode})
-    let idx = genField(c, le[0].sons[1])
+    let idx = genField(c, le[0][1])
     let tmp = c.genx(ri)
     c.preventFalseAlias(le[0], opcWrObj, objR, idx, tmp)
     c.freeTemp(tmp)
     c.freeTemp(idx)
     c.freeTemp(objR)
   of nkDotExpr:
-    let dest = c.genx(le.sons[0], {gfNode})
-    let idx = genField(c, le.sons[1])
+    let dest = c.genx(le[0], {gfNode})
+    let idx = genField(c, le[1])
     let tmp = c.genx(ri)
     c.preventFalseAlias(le, opcWrObj, dest, idx, tmp)
     c.freeTemp(idx)
     c.freeTemp(tmp)
     c.freeTemp(dest)
   of nkDerefExpr, nkHiddenDeref:
-    let dest = c.genx(le.sons[0], {gfNode})
+    let dest = c.genx(le[0], {gfNode})
     let tmp = c.genx(ri)
     c.preventFalseAlias(le, opcWrDeref, dest, 0, tmp)
     c.freeTemp(dest)
@@ -1584,7 +1583,7 @@ proc importcCond*(s: PSym): bool {.inline.} =
   ## return true to importc `s`, false to execute its body instead (refs #8405)
   if sfImportc in s.flags:
     if s.kind in routineKinds:
-      return s.ast.sons[bodyPos].kind == nkEmpty
+      return s.ast[bodyPos].kind == nkEmpty
 
 proc importcSym(c: PCtx; info: TLineInfo; s: PSym) =
   when hasFFI:
@@ -1659,8 +1658,8 @@ template needsRegLoad(): untyped =
 
 proc genArrAccessOpcode(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
                         flags: TGenFlags) =
-  let a = c.genx(n.sons[0], flags)
-  let b = c.genIndex(n.sons[1], n.sons[0].typ)
+  let a = c.genx(n[0], flags)
+  let b = c.genIndex(n[1], n[0].typ)
   if dest < 0: dest = c.getTemp(n.typ)
   if opc == opcLdArr and {gfNodeAddr} * flags != {}:
     c.gABC(n, opcLdArrAddr, dest, a, b)
@@ -1677,8 +1676,8 @@ proc genArrAccessOpcode(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
   c.freeTemp(b)
 
 proc genObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
-  let a = c.genx(n.sons[0], flags)
-  let b = genField(c, n.sons[1])
+  let a = c.genx(n[0], flags)
+  let b = genField(c, n[1])
   if dest < 0: dest = c.getTemp(n.typ)
   if {gfNodeAddr} * flags != {}:
     c.gABC(n, opcLdObjAddr, dest, a, b)
@@ -1750,7 +1749,7 @@ proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
   c.freeTemp(objR)
 
 proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
-  let arrayType = n.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind
+  let arrayType = n[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind
   if arrayType in {tyString, tyCString}:
     genArrAccessOpcode(c, n, dest, opcLdStrIdx, {})
   elif arrayType == tyTypeDesc:
@@ -1759,21 +1758,21 @@ proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
     genArrAccessOpcode(c, n, dest, opcLdArr, flags)
 
 proc getNullValueAux(t: PType; obj: PNode, result: PNode; conf: ConfigRef; currPosition: var int) =
-  if t != nil and t.len > 0 and t.sons[0] != nil:
-    let b = skipTypes(t.sons[0], skipPtrs)
+  if t != nil and t.len > 0 and t[0] != nil:
+    let b = skipTypes(t[0], skipPtrs)
     getNullValueAux(b, b.n, result, conf, currPosition)
   case obj.kind
   of nkRecList:
-    for i in 0 ..< len(obj): getNullValueAux(nil, obj.sons[i], result, conf, currPosition)
+    for i in 0..<obj.len: getNullValueAux(nil, obj[i], result, conf, currPosition)
   of nkRecCase:
-    getNullValueAux(nil, obj.sons[0], result, conf, currPosition)
-    for i in 1 ..< len(obj):
-      getNullValueAux(nil, lastSon(obj.sons[i]), result, conf, currPosition)
+    getNullValueAux(nil, obj[0], result, conf, currPosition)
+    for i in 1..<obj.len:
+      getNullValueAux(nil, lastSon(obj[i]), result, conf, currPosition)
   of nkSym:
     let field = newNodeI(nkExprColonExpr, result.info)
     field.add(obj)
     field.add(getNullValue(obj.sym.typ, result.info, conf))
-    addSon(result, field)
+    result.add field
     doAssert obj.sym.position == currPosition
     inc currPosition
   else: globalError(conf, result.info, "cannot create null element for: " & $obj)
@@ -1808,12 +1807,12 @@ proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode =
     getNullValueAux(t, t.n, result, conf, currPosition)
   of tyArray:
     result = newNodeIT(nkBracket, info, t)
-    for i in 0 ..< toInt(lengthOrd(conf, t)):
-      addSon(result, getNullValue(elemType(t), info, conf))
+    for i in 0..<toInt(lengthOrd(conf, t)):
+      result.add getNullValue(elemType(t), info, conf)
   of tyTuple:
     result = newNodeIT(nkTupleConstr, info, t)
-    for i in 0 ..< len(t):
-      addSon(result, getNullValue(t.sons[i], info, conf))
+    for i in 0..<t.len:
+      result.add getNullValue(t[i], info, conf)
   of tySet:
     result = newNodeIT(nkCurly, info, t)
   of tyOpt:
@@ -1827,16 +1826,16 @@ proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode =
 proc genVarSection(c: PCtx; n: PNode) =
   for a in n:
     if a.kind == nkCommentStmt: continue
-    #assert(a.sons[0].kind == nkSym) can happen for transformed vars
+    #assert(a[0].kind == nkSym) can happen for transformed vars
     if a.kind == nkVarTuple:
-      for i in 0 .. a.len-3:
+      for i in 0..<a.len-2:
         if a[i].kind == nkSym:
           if not a[i].sym.isGlobal: setSlot(c, a[i].sym)
           checkCanEval(c, a[i])
       c.gen(lowerTupleUnpacking(c.graph, a, c.getOwner))
-    elif a.sons[0].kind == nkSym:
-      let s = a.sons[0].sym
-      checkCanEval(c, a.sons[0])
+    elif a[0].kind == nkSym:
+      let s = a[0].sym
+      checkCanEval(c, a[0])
       if s.isGlobal:
         if s.position == 0:
           if importcCond(s): c.importcSym(a.info, s)
@@ -1847,37 +1846,37 @@ proc genVarSection(c: PCtx; n: PNode) =
             assert sa.kind != nkCall
             c.globals.add(sa)
             s.position = c.globals.len
-        if a.sons[2].kind != nkEmpty:
-          let tmp = c.genx(a.sons[0], {gfNodeAddr})
-          let val = c.genx(a.sons[2])
-          c.genAdditionalCopy(a.sons[2], opcWrDeref, tmp, 0, val)
+        if a[2].kind != nkEmpty:
+          let tmp = c.genx(a[0], {gfNodeAddr})
+          let val = c.genx(a[2])
+          c.genAdditionalCopy(a[2], opcWrDeref, tmp, 0, val)
           c.freeTemp(val)
           c.freeTemp(tmp)
       else:
         setSlot(c, s)
-        if a.sons[2].kind == nkEmpty:
+        if a[2].kind == nkEmpty:
           c.gABx(a, ldNullOpcode(s.typ), s.position, c.genType(s.typ))
         else:
           assert s.typ != nil
           if not fitsRegister(s.typ):
             c.gABx(a, ldNullOpcode(s.typ), s.position, c.genType(s.typ))
-          let le = a.sons[0]
+          let le = a[0]
           assert le.typ != nil
           if not fitsRegister(le.typ) and s.kind in {skResult, skVar, skParam}:
             var cc = c.getTemp(le.typ)
-            gen(c, a.sons[2], cc)
+            gen(c, a[2], cc)
             c.gABC(le, whichAsgnOpc(le), s.position.TRegister, cc)
             c.freeTemp(cc)
           else:
-            gen(c, a.sons[2], s.position.TRegister)
+            gen(c, a[2], s.position.TRegister)
     else:
-      # assign to a.sons[0]; happens for closures
-      if a.sons[2].kind == nkEmpty:
-        let tmp = genx(c, a.sons[0])
-        c.gABx(a, ldNullOpcode(a[0].typ), tmp, c.genType(a.sons[0].typ))
+      # assign to a[0]; happens for closures
+      if a[2].kind == nkEmpty:
+        let tmp = genx(c, a[0])
+        c.gABx(a, ldNullOpcode(a[0].typ), tmp, c.genType(a[0].typ))
         c.freeTemp(tmp)
       else:
-        genAsgn(c, a.sons[0], a.sons[2], true)
+        genAsgn(c, a[0], a[2], true)
 
 proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) =
   if dest < 0: dest = c.getTemp(n.typ)
@@ -1907,8 +1906,8 @@ proc genSetConstr(c: PCtx, n: PNode, dest: var TDest) =
   c.gABx(n, opcLdNull, dest, c.genType(n.typ))
   for x in n:
     if x.kind == nkRange:
-      let a = c.genx(x.sons[0])
-      let b = c.genx(x.sons[1])
+      let a = c.genx(x[0])
+      let b = c.genx(x[1])
       c.gABC(n, opcInclRange, dest, a, b)
       c.freeTemp(b)
       c.freeTemp(a)
@@ -1921,15 +1920,15 @@ proc genObjConstr(c: PCtx, n: PNode, dest: var TDest) =
   if dest < 0: dest = c.getTemp(n.typ)
   let t = n.typ.skipTypes(abstractRange+{tyOwned}-{tyTypeDesc})
   if t.kind == tyRef:
-    c.gABx(n, opcNew, dest, c.genType(t.sons[0]))
+    c.gABx(n, opcNew, dest, c.genType(t[0]))
   else:
     c.gABx(n, opcLdNull, dest, c.genType(n.typ))
   for i in 1..<n.len:
-    let it = n.sons[i]
-    if it.kind == nkExprColonExpr and it.sons[0].kind == nkSym:
-      let idx = genField(c, it.sons[0])
-      let tmp = c.genx(it.sons[1])
-      c.preventFalseAlias(it.sons[1], opcWrObj,
+    let it = n[i]
+    if it.kind == nkExprColonExpr and it[0].kind == nkSym:
+      let idx = genField(c, it[0])
+      let tmp = c.genx(it[1])
+      c.preventFalseAlias(it[1], opcWrObj,
                           dest, idx, tmp)
       c.freeTemp(tmp)
     else:
@@ -1940,11 +1939,11 @@ proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
   c.gABx(n, opcLdNull, dest, c.genType(n.typ))
   # XXX x = (x.old, 22)  produces wrong code ... stupid self assignments
   for i in 0..<n.len:
-    let it = n.sons[i]
+    let it = n[i]
     if it.kind == nkExprColonExpr:
-      let idx = genField(c, it.sons[0])
-      let tmp = c.genx(it.sons[1])
-      c.preventFalseAlias(it.sons[1], opcWrObj,
+      let idx = genField(c, it[0])
+      let tmp = c.genx(it[1])
+      c.preventFalseAlias(it[1], opcWrObj,
                           dest, idx, tmp)
       c.freeTemp(tmp)
     else:
@@ -1957,22 +1956,18 @@ proc genProc*(c: PCtx; s: PSym): int
 proc matches(s: PSym; x: string): bool =
   let y = x.split('.')
   var s = s
-  var L = y.len-1
-  while L >= 0:
-    if s == nil or (y[L].cmpIgnoreStyle(s.name.s) != 0 and y[L] != "*"):
+  for i in 1..y.len:
+    if s == nil or (y[^i].cmpIgnoreStyle(s.name.s) != 0 and y[^i] != "*"):
       return false
     s = s.owner
-    dec L
   result = true
 
 proc matches(s: PSym; y: varargs[string]): bool =
   var s = s
-  var L = y.len-1
-  while L >= 0:
-    if s == nil or (y[L].cmpIgnoreStyle(s.name.s) != 0 and y[L] != "*"):
+  for i in 1..y.len:
+    if s == nil or (y[^i].cmpIgnoreStyle(s.name.s) != 0 and y[^i] != "*"):
       return false
     s = if sfFromGeneric in s.flags: s.owner.owner else: s.owner
-    dec L
   result = true
 
 proc procIsCallback(c: PCtx; s: PSym): bool =
@@ -2021,8 +2016,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     else:
       globalError(c.config, n.info, "cannot generate code for: " & s.name.s)
   of nkCallKinds:
-    if n.sons[0].kind == nkSym:
-      let s = n.sons[0].sym
+    if n[0].kind == nkSym:
+      let s = n[0].sym
       if s.magic != mNone:
         genMagic(c, n, dest, s.magic)
       elif s.kind == skMethod:
@@ -2052,7 +2047,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     else: unused(c, n, dest)
   of nkAsgn, nkFastAsgn:
     unused(c, n, dest)
-    genAsgn(c, n.sons[0], n.sons[1], n.kind == nkAsgn)
+    genAsgn(c, n[0], n[1], n.kind == nkAsgn)
   of nkDotExpr: genObjAccess(c, n, dest, flags)
   of nkCheckedFieldExpr: genCheckedObjAccess(c, n, dest, flags)
   of nkBracketExpr: genArrAccess(c, n, dest, flags)
@@ -2061,7 +2056,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
   of nkIfStmt, nkIfExpr: genIf(c, n, dest)
   of nkWhenStmt:
     # This is "when nimvm" node. Chose the first branch.
-    gen(c, n.sons[0].sons[1], dest)
+    gen(c, n[0][1], dest)
   of nkCaseStmt: genCase(c, n, dest)
   of nkWhileStmt:
     unused(c, n, dest)
@@ -2081,34 +2076,33 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     # XXX Fix this bug properly, lexim triggers it
     for x in n: gen(c, x)
   of nkStmtListExpr:
-    let L = n.len-1
-    for i in 0 ..< L: gen(c, n.sons[i])
-    gen(c, n.sons[L], dest, flags)
+    for i in 0..<n.len-1: gen(c, n[i])
+    gen(c, n[^1], dest, flags)
   of nkPragmaBlock:
     gen(c, n.lastSon, dest, flags)
   of nkDiscardStmt:
     unused(c, n, dest)
-    gen(c, n.sons[0])
+    gen(c, n[0])
   of nkHiddenStdConv, nkHiddenSubConv, nkConv:
-    genConv(c, n, n.sons[1], dest)
+    genConv(c, n, n[1], dest)
   of nkObjDownConv:
-    genConv(c, n, n.sons[0], dest)
+    genConv(c, n, n[0], dest)
   of nkObjUpConv:
-    genConv(c, n, n.sons[0], dest)
+    genConv(c, n, n[0], dest)
   of nkVarSection, nkLetSection:
     unused(c, n, dest)
     genVarSection(c, n)
   of declarativeDefs, nkMacroDef:
     unused(c, n, dest)
   of nkLambdaKinds:
-    #let s = n.sons[namePos].sym
+    #let s = n[namePos].sym
     #discard genProc(c, s)
-    genLit(c, newSymNode(n.sons[namePos].sym), dest)
+    genLit(c, newSymNode(n[namePos].sym), dest)
   of nkChckRangeF, nkChckRange64, nkChckRange:
     let
-      tmp0 = c.genx(n.sons[0])
-      tmp1 = c.genx(n.sons[1])
-      tmp2 = c.genx(n.sons[2])
+      tmp0 = c.genx(n[0])
+      tmp1 = c.genx(n[1])
+      tmp2 = c.genx(n[2])
     c.gABC(n, opcRangeChck, tmp0, tmp1, tmp2)
     c.freeTemp(tmp1)
     c.freeTemp(tmp2)
@@ -2121,14 +2115,14 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
      nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt, nkExportStmt:
     unused(c, n, dest)
   of nkStringToCString, nkCStringToString:
-    gen(c, n.sons[0], dest)
+    gen(c, n[0], dest)
   of nkBracket: genArrayConstr(c, n, dest)
   of nkCurly: genSetConstr(c, n, dest)
   of nkObjConstr: genObjConstr(c, n, dest)
   of nkPar, nkClosure, nkTupleConstr: genTupleConstr(c, n, dest)
   of nkCast:
     if allowCast in c.features:
-      genConv(c, n, n.sons[1], dest, opcCast)
+      genConv(c, n, n[1], dest, opcCast)
     else:
       genCastIntFloat(c, n, dest)
   of nkTypeOfExpr:
@@ -2186,14 +2180,14 @@ proc finalJumpTarget(c: PCtx; pc, diff: int) =
 proc genGenericParams(c: PCtx; gp: PNode) =
   var base = c.prc.maxSlots
   for i in 0..<gp.len:
-    var param = gp.sons[i].sym
+    var param = gp[i].sym
     param.position = base + i # XXX: fix this earlier; make it consistent with templates
     c.prc.slots[base + i] = (inUse: true, kind: slotFixedLet)
   c.prc.maxSlots = base + gp.len
 
 proc optimizeJumps(c: PCtx; start: int) =
   const maxIterations = 10
-  for i in start ..< c.code.len:
+  for i in start..<c.code.len:
     let opc = c.code[i].opcode
     case opc
     of opcTJmp, opcFJmp:
@@ -2233,7 +2227,7 @@ proc optimizeJumps(c: PCtx; start: int) =
     else: discard
 
 proc genProc(c: PCtx; s: PSym): int =
-  var x = s.ast.sons[miscPos]
+  var x = s.ast[miscPos]
   if x.kind == nkEmpty or x[0].kind == nkEmpty:
     #if s.name.s == "outterMacro" or s.name.s == "innerProc":
     #  echo "GENERATING CODE FOR ", s.name.s
@@ -2248,8 +2242,8 @@ proc genProc(c: PCtx; s: PSym): int =
     if x.kind == nkEmpty:
       x = newTree(nkBracket, newIntNode(nkIntLit, result), x)
     else:
-      x.sons[0] = newIntNode(nkIntLit, result)
-    s.ast.sons[miscPos] = x
+      x[0] = newIntNode(nkIntLit, result)
+    s.ast[miscPos] = x
     # thanks to the jmp we can add top level statements easily and also nest
     # procs easily:
     let body = transformBody(c.graph, s, cache = not isCompileTimeProc(s))
@@ -2265,7 +2259,7 @@ proc genProc(c: PCtx; s: PSym): int =
       genGenericParams(c, s.ast[genericParamsPos])
 
     if tfCapturesEnv in s.typ.flags:
-      #let env = s.ast.sons[paramsPos].lastSon.sym
+      #let env = s.ast[paramsPos].lastSon.sym
       #assert env.position == 2
       c.prc.slots[c.prc.maxSlots] = (inUse: true, kind: slotFixedLet)
       inc c.prc.maxSlots
diff --git a/compiler/vmmarshal.nim b/compiler/vmmarshal.nim
index 8443890e5..541fef890 100644
--- a/compiler/vmmarshal.nim
+++ b/compiler/vmmarshal.nim
@@ -18,16 +18,16 @@ proc ptrToInt(x: PNode): int {.inline.} =
 proc getField(n: PNode; position: int): PSym =
   case n.kind
   of nkRecList:
-    for i in 0 ..< len(n):
-      result = getField(n.sons[i], position)
+    for i in 0..<n.len:
+      result = getField(n[i], position)
       if result != nil: return
   of nkRecCase:
-    result = getField(n.sons[0], position)
+    result = getField(n[0], position)
     if result != nil: return
-    for i in 1 ..< len(n):
-      case n.sons[i].kind
+    for i in 1..<n.len:
+      case n[i].kind
       of nkOfBranch, nkElse:
-        result = getField(lastSon(n.sons[i]), position)
+        result = getField(lastSon(n[i]), position)
         if result != nil: return
       else: discard
   of nkSym:
@@ -39,15 +39,15 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet; conf: Confi
 proc storeObj(s: var string; typ: PType; x: PNode; stored: var IntSet; conf: ConfigRef) =
   assert x.kind == nkObjConstr
   let start = 1
-  for i in start ..< len(x):
+  for i in start..<x.len:
     if i > start: s.add(", ")
-    var it = x.sons[i]
+    var it = x[i]
     if it.kind == nkExprColonExpr:
-      if it.sons[0].kind == nkSym:
-        let field = it.sons[0].sym
+      if it[0].kind == nkSym:
+        let field = it[0].sym
         s.add(escapeJson(field.name.s))
         s.add(": ")
-        storeAny(s, field.typ, it.sons[1], stored, conf)
+        storeAny(s, field.typ, it[1], stored, conf)
     elif typ.n != nil:
       let field = getField(typ.n, i)
       s.add(escapeJson(field.name.s))
@@ -57,7 +57,7 @@ proc storeObj(s: var string; typ: PType; x: PNode; stored: var IntSet; conf: Con
 proc skipColon*(n: PNode): PNode =
   result = n
   if n.kind == nkExprColonExpr:
-    result = n.sons[1]
+    result = n[1]
 
 proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet;
               conf: ConfigRef) =
@@ -74,7 +74,7 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet;
     if t.kind == tySequence and a.kind == nkNilLit: s.add("null")
     else:
       s.add("[")
-      for i in 0 .. a.len-1:
+      for i in 0..<a.len:
         if i > 0: s.add(", ")
         storeAny(s, t.elemType, a[i], stored, conf)
       s.add("]")
@@ -84,7 +84,7 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet;
       if i > 0: s.add(", ")
       s.add("\"Field" & $i)
       s.add("\": ")
-      storeAny(s, t.sons[i], a[i].skipColon, stored, conf)
+      storeAny(s, t[i], a[i].skipColon, stored, conf)
     s.add("}")
   of tyObject:
     s.add("{")
@@ -203,7 +203,7 @@ proc loadAny(p: var JsonParser, t: PType,
       next(p)
       if i >= t.len:
         raiseParseErr(p, "too many fields to tuple type " & typeToString(t))
-      result.add loadAny(p, t.sons[i], tab, cache, conf)
+      result.add loadAny(p, t[i], tab, cache, conf)
       inc i
     if p.kind == jsonObjectEnd: next(p)
     else: raiseParseErr(p, "'}' end of object expected")
@@ -221,12 +221,12 @@ proc loadAny(p: var JsonParser, t: PType,
         raiseParseErr(p, "unknown field for object of type " & typeToString(t))
       next(p)
       let pos = field.position + 1
-      if pos >= result.sons.len:
+      if pos >= result.len:
         setLen(result.sons, pos + 1)
       let fieldNode = newNode(nkExprColonExpr)
-      fieldNode.addSon(newSymNode(newSym(skField, ident, nil, unknownLineInfo())))
-      fieldNode.addSon(loadAny(p, field.typ, tab, cache, conf))
-      result.sons[pos] = fieldNode
+      fieldNode.add newSymNode(newSym(skField, ident, nil, unknownLineInfo()))
+      fieldNode.add loadAny(p, field.typ, tab, cache, conf)
+      result[pos] = fieldNode
     if p.kind == jsonObjectEnd: next(p)
     else: raiseParseErr(p, "'}' end of object expected")
   of tySet:
diff --git a/compiler/vmops.nim b/compiler/vmops.nim
index b46faeb0f..1e3a258f3 100644
--- a/compiler/vmops.nim
+++ b/compiler/vmops.nim
@@ -91,7 +91,7 @@ template wrapDangerous(op, modop) {.dirty.} =
 
 proc getCurrentExceptionMsgWrapper(a: VmArgs) {.nimcall.} =
   setResult(a, if a.currentException.isNil: ""
-               else: a.currentException.sons[3].skipColon.strVal)
+               else: a.currentException[3].skipColon.strVal)
 
 proc getCurrentExceptionWrapper(a: VmArgs) {.nimcall.} =
   setResult(a, a.currentException)
@@ -191,7 +191,7 @@ proc registerAdditionalOps*(c: PCtx) =
     let ePos = a.getInt(2).int
     let arr = a.getNode(0)
     var bytes = newSeq[byte](arr.len)
-    for i in 0 ..< arr.len:
+    for i in 0..<arr.len:
       bytes[i] = byte(arr[i].intVal and 0xff)
 
     var res = hashes.hash(bytes, sPos, ePos)
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index f2946ffa2..d03c22952 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -174,7 +174,7 @@ const
     ]
 
 proc findStr*(a: openArray[string], s: string): int =
-  for i in low(a) .. high(a):
+  for i in low(a)..high(a):
     if cmpIgnoreStyle(a[i], s) == 0:
       return i
   result = - 1
diff --git a/compiler/writetracking.nim b/compiler/writetracking.nim
index 635224723..3db60a19a 100644
--- a/compiler/writetracking.nim
+++ b/compiler/writetracking.nim
@@ -58,32 +58,32 @@ proc allRoots(n: PNode; result: var seq[ptr TSym]; info: var set[RootInfo]) =
       result.add(cast[ptr TSym](n.sym))
   of nkHiddenDeref, nkDerefExpr:
     incl(info, rootIsHeapAccess)
-    allRoots(n.sons[0], result, info)
+    allRoots(n[0], result, info)
   of nkDotExpr, nkBracketExpr, nkCheckedFieldExpr,
       nkHiddenAddr, nkObjUpConv, nkObjDownConv:
-    allRoots(n.sons[0], result, info)
+    allRoots(n[0], result, info)
   of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv, nkConv,
       nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkOfBranch,
       nkElifBranch, nkElse, nkExceptBranch, nkFinally, nkCast:
     allRoots(n.lastSon, result, info)
   of nkCallKinds:
     if getMagic(n) == mSlice:
-      allRoots(n.sons[1], result, info)
+      allRoots(n[1], result, info)
     else:
       # we do significantly better here by using the available escape
       # information:
-      if n.sons[0].typ.isNil: return
-      var typ = n.sons[0].typ
+      if n[0].typ.isNil: return
+      var typ = n[0].typ
       if typ != nil:
         typ = skipTypes(typ, abstractInst)
         if typ.kind != tyProc: typ = nil
-        else: assert(len(typ) == len(typ.n))
+        else: assert(typ.len == typ.n.len)
 
-      for i in 1 ..< n.len:
-        let it = n.sons[i]
-        if typ != nil and i < len(typ):
-          assert(typ.n.sons[i].kind == nkSym)
-          let paramType = typ.n.sons[i]
+      for i in 1..<n.len:
+        let it = n[i]
+        if typ != nil and i < typ.len:
+          assert(typ.n[i].kind == nkSym)
+          let paramType = typ.n[i]
           if paramType.typ.isCompileTimeOnly: continue
           if sfEscapes in paramType.sym.flags or paramType.typ.kind == tyVar:
             allRoots(it, result, info)
@@ -91,7 +91,7 @@ proc allRoots(n: PNode; result: var seq[ptr TSym]; info: var set[RootInfo]) =
           allRoots(it, result, info)
   else:
     for i in 0..<n.safeLen:
-      allRoots(n.sons[i], result, info)
+      allRoots(n[i], result, info)
 
 proc addAsgn(a: var Assignment; dest, src: PNode; destInfo: set[RootInfo]) =
   a.dest = @[]
@@ -108,7 +108,7 @@ proc addAsgn(a: var Assignment; dest, src: PNode; destInfo: set[RootInfo]) =
   #echo "ADDING ", dest.info, " ", a.destInfo
 
 proc srcHasSym(a: Assignment; x: ptr TSym): bool =
-  for i in 0 ..< a.srcNoTc:
+  for i in 0..<a.srcNoTc:
     if a.src[i] == x: return true
 
 proc returnsNewExpr*(n: PNode): NewLocation =
@@ -123,14 +123,14 @@ proc returnsNewExpr*(n: PNode): NewLocation =
   of nkCurly, nkBracket, nkPar, nkTupleConstr, nkObjConstr, nkClosure,
       nkIfExpr, nkIfStmt, nkWhenStmt, nkCaseStmt, nkTryStmt, nkHiddenTryStmt:
     result = newLit
-    for i in ord(n.kind == nkObjConstr) ..< n.len:
-      let x = returnsNewExpr(n.sons[i])
+    for i in ord(n.kind == nkObjConstr)..<n.len:
+      let x = returnsNewExpr(n[i])
       case x
       of newNone: return newNone
       of newLit: discard
       of newCall: result = newCall
   of nkCallKinds:
-    if n.sons[0].typ != nil and tfReturnsNew in n.sons[0].typ.flags:
+    if n[0].typ != nil and tfReturnsNew in n[0].typ.flags:
       result = newCall
   else:
     result = newNone
@@ -148,21 +148,20 @@ proc deps(w: var W; dest, src: PNode; destInfo: set[RootInfo]) =
   # rule out obviously innocent assignments like 'somebool = true'
   if dest.kind == nkSym and retNew == newLit: discard
   else:
-    let L = w.assignments.len
-    w.assignments.setLen(L+1)
-    addAsgn(w.assignments[L], dest, src, destInfo)
+    w.assignments.setLen(w.assignments.len+1)
+    addAsgn(w.assignments[^1], dest, src, destInfo)
 
 proc depsArgs(w: var W; n: PNode) =
-  if n.sons[0].typ.isNil: return
-  var typ = skipTypes(n.sons[0].typ, abstractInst)
+  if n[0].typ.isNil: return
+  var typ = skipTypes(n[0].typ, abstractInst)
   if typ.kind != tyProc: return
   # echo n.info, " ", n, " ", w.owner.name.s, " ", typeToString(typ)
-  assert(len(typ) == len(typ.n))
-  for i in 1 ..< n.len:
-    let it = n.sons[i]
-    if i < len(typ):
-      assert(typ.n.sons[i].kind == nkSym)
-      let paramType = typ.n.sons[i]
+  assert(typ.len == typ.n.len)
+  for i in 1..<n.len:
+    let it = n[i]
+    if i < typ.len:
+      assert(typ.n[i].kind == nkSym)
+      let paramType = typ.n[i]
       if paramType.typ.isCompileTimeOnly: continue
       var destInfo: set[RootInfo] = {}
       if sfWrittenTo in paramType.sym.flags or paramType.typ.kind == tyVar:
@@ -181,20 +180,20 @@ proc deps(w: var W; n: PNode) =
       if last.kind == nkEmpty: continue
       if child.kind == nkVarTuple and last.kind in {nkPar, nkTupleConstr}:
         if child.len-2 != last.len: return
-        for i in 0 .. child.len-3:
-          deps(w, child.sons[i], last.sons[i], {})
+        for i in 0..<child.len-2:
+          deps(w, child[i], last[i], {})
       else:
-        for i in 0 .. child.len-3:
-          deps(w, child.sons[i], last, {})
+        for i in 0..<child.len-2:
+          deps(w, child[i], last, {})
   of nkAsgn, nkFastAsgn:
-    deps(w, n.sons[0], n.sons[1], {})
+    deps(w, n[0], n[1], {})
   else:
-    for i in 0 ..< n.safeLen:
-      deps(w, n.sons[i])
+    for i in 0..<n.safeLen:
+      deps(w, n[i])
     if n.kind in nkCallKinds:
       if getMagic(n) in {mNew, mNewFinalize, mNewSeq}:
         # may not look like an assignment, but it is:
-        deps(w, n.sons[1], newNodeIT(nkObjConstr, n.info, n.sons[1].typ), {})
+        deps(w, n[1], newNodeIT(nkObjConstr, n.info, n[1].typ), {})
       else:
         depsArgs(w, n)
 
@@ -211,14 +210,14 @@ proc possibleAliases(w: var W; result: var seq[ptr TSym]) =
   while todo < result.len:
     let x = result[todo]
     inc todo
-    for i in 0..<len(w.assignments):
+    for i in 0..<w.assignments.len:
       let a = addr(w.assignments[i])
       #if a.srcHasSym(x):
       #  # y = f(..., x, ...)
-      #  for i in 0 ..< a.destNoTc: addNoDup a.dest[i]
+      #  for i in 0..<a.destNoTc: addNoDup a.dest[i]
       if a.destNoTc > 0 and a.dest[0] == x and rootIsSym in a.destInfo:
         # x = f(..., y, ....)
-        for i in 0 ..< a.srcNoTc: addNoDup a.src[i]
+        for i in 0..<a.srcNoTc: addNoDup a.src[i]
 
 proc markWriteOrEscape(w: var W; conf: ConfigRef) =
   ## Both 'writes' and 'escapes' effects ultimately only care
@@ -226,7 +225,7 @@ proc markWriteOrEscape(w: var W; conf: ConfigRef) =
   ## However, due to aliasing, even locals that might not look as parameters
   ## have to count as parameters if they can alias a parameter:
   ##
-  ## .. code-block:: nim
+  ##..code-block:: nim
   ##   proc modifies(n: Node) {.writes: [n].} =
   ##     let x = n
   ##     x.data = "abc"
@@ -239,7 +238,7 @@ proc markWriteOrEscape(w: var W; conf: ConfigRef) =
   ## A write then looks like ``p[] = x``.
   ## An escape looks like ``p[] = q`` or more generally
   ## like ``p[] = f(q)`` where ``f`` can forward ``q``.
-  for i in 0..<len(w.assignments):
+  for i in 0..<w.assignments.len:
     let a = addr(w.assignments[i])
     if a.destInfo != {}:
       possibleAliases(w, a.dest)
@@ -271,6 +270,6 @@ proc trackWrites*(owner: PSym; body: PNode; conf: ConfigRef) =
   deps(w, body)
   # Phase 2: Compute the 'writes' and 'escapes' effects:
   markWriteOrEscape(w, conf)
-  if w.returnsNew != asgnOther and not isEmptyType(owner.typ.sons[0]) and
-      containsGarbageCollectedRef(owner.typ.sons[0]):
+  if w.returnsNew != asgnOther and not isEmptyType(owner.typ[0]) and
+      containsGarbageCollectedRef(owner.typ[0]):
     incl(owner.typ.flags, tfReturnsNew)