summary refs log tree commit diff stats
path: root/compiler/semstmts.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/semstmts.nim')
-rw-r--r--compiler/semstmts.nim679
1 files changed, 336 insertions, 343 deletions
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