summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2023-11-20 21:12:13 +0100
committerGitHub <noreply@github.com>2023-11-20 21:12:13 +0100
commit02be027e9b3c146c0a594c3ea4fae7152fd8b974 (patch)
treeb9a95b4b29df31be23dafda1dcdc1ab4e2762372
parentcecaf9c56b1240a44a4de837e03694a0c55ec379 (diff)
downloadNim-02be027e9b3c146c0a594c3ea4fae7152fd8b974.tar.gz
IC: progress and refactorings (#22961)
-rw-r--r--compiler/ast.nim34
-rw-r--r--compiler/ccgtypes.nim18
-rw-r--r--compiler/cgmeth.nim2
-rw-r--r--compiler/closureiters.nim4
-rw-r--r--compiler/commands.nim1
-rw-r--r--compiler/concepts.nim4
-rw-r--r--compiler/enumtostr.nim4
-rw-r--r--compiler/errorhandling.nim6
-rw-r--r--compiler/guards.nim4
-rw-r--r--compiler/ic/bitabs.nim6
-rw-r--r--compiler/ic/cbackend.nim6
-rw-r--r--compiler/ic/dce.nim8
-rw-r--r--compiler/ic/ic.nim300
-rw-r--r--compiler/ic/integrity.nim12
-rw-r--r--compiler/ic/navigator.nim14
-rw-r--r--compiler/ic/packed_ast.nim157
-rw-r--r--compiler/importer.nim3
-rw-r--r--compiler/injectdestructors.nim2
-rw-r--r--compiler/lambdalifting.nim10
-rw-r--r--compiler/liftdestructors.nim4
-rw-r--r--compiler/lowerings.nim4
-rw-r--r--compiler/magicsys.nim10
-rw-r--r--compiler/main.nim12
-rw-r--r--compiler/modulegraphs.nim8
-rw-r--r--compiler/nilcheck.nim4
-rw-r--r--compiler/options.nim22
-rw-r--r--compiler/passes.nim6
-rw-r--r--compiler/pipelines.nim8
-rw-r--r--compiler/plugins/itersgen.nim2
-rw-r--r--compiler/sem.nim14
-rw-r--r--compiler/semdata.nim26
-rw-r--r--compiler/semexprs.nim6
-rw-r--r--compiler/semfold.nim6
-rw-r--r--compiler/semmagic.nim12
-rw-r--r--compiler/semobjconstr.nim2
-rw-r--r--compiler/semparallel.nim2
-rw-r--r--compiler/semstmts.nim10
-rw-r--r--compiler/semtypes.nim25
-rw-r--r--compiler/semtypinst.nim4
-rw-r--r--compiler/sigmatch.nim10
-rw-r--r--compiler/sinkparameter_inference.nim2
-rw-r--r--compiler/spawn.nim8
-rw-r--r--compiler/types.nim4
-rw-r--r--compiler/vm.nim4
-rw-r--r--compiler/vmdeps.nim6
45 files changed, 456 insertions, 360 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 661a82703..8a71522e6 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -1166,7 +1166,7 @@ proc idGeneratorFromModule*(m: PSym): IdGenerator =
 proc idGeneratorForPackage*(nextIdWillBe: int32): IdGenerator =
   result = IdGenerator(module: PackageModuleId, symId: nextIdWillBe - 1'i32, typeId: 0, disambTable: initCountTable[PIdent]())
 
-proc nextSymId*(x: IdGenerator): ItemId {.inline.} =
+proc nextSymId(x: IdGenerator): ItemId {.inline.} =
   assert(not x.sealed)
   inc x.symId
   result = ItemId(module: x.module, item: x.symId)
@@ -1547,7 +1547,8 @@ iterator items*(t: PType): PType =
 iterator pairs*(n: PType): tuple[i: int, n: PType] =
   for i in 0..<n.sons.len: yield (i, n.sons[i])
 
-proc newType*(kind: TTypeKind, id: ItemId; owner: PSym, sons: seq[PType] = @[]): PType =
+proc newType*(kind: TTypeKind, idgen: IdGenerator; owner: PSym, sons: seq[PType] = @[]): PType =
+  let id = nextTypeId idgen
   result = PType(kind: kind, owner: owner, size: defaultSize,
                  align: defaultAlignment, itemId: id,
                  uniqueId: id, sons: sons)
@@ -1556,12 +1557,15 @@ proc newType*(kind: TTypeKind, id: ItemId; owner: PSym, sons: seq[PType] = @[]):
       echo "KNID ", kind
       writeStackTrace()
 
-template newType*(kind: TTypeKind, id: ItemId; owner: PSym, parent: PType): PType =
+template newType*(kind: TTypeKind, id: IdGenerator; owner: PSym, parent: PType): PType =
   newType(kind, id, owner, parent.sons)
 
-proc newType*(prev: PType, sons: seq[PType]): PType =
-  result = prev
-  result.sons = sons
+proc setSons*(dest: PType; sons: seq[PType]) {.inline.} = dest.sons = sons
+
+when false:
+  proc newType*(prev: PType, sons: seq[PType]): PType =
+    result = prev
+    result.sons = sons
 
 proc addSon*(father, son: PType) =
   # todo fixme: in IC, `son` might be nil
@@ -1595,13 +1599,17 @@ proc assignType*(dest, src: PType) =
   newSons(dest, src.len)
   for i in 0..<src.len: dest[i] = src[i]
 
-proc copyType*(t: PType, id: ItemId, owner: PSym): PType =
-  result = newType(t.kind, id, owner)
+proc copyType*(t: PType, idgen: IdGenerator, owner: PSym): PType =
+  result = newType(t.kind, idgen, owner)
   assignType(result, t)
   result.sym = t.sym          # backend-info should not be copied
 
 proc exactReplica*(t: PType): PType =
-  result = copyType(t, t.itemId, t.owner)
+  result = PType(kind: t.kind, owner: t.owner, size: defaultSize,
+                 align: defaultAlignment, itemId: t.itemId,
+                 uniqueId: t.uniqueId)
+  assignType(result, t)
+  result.sym = t.sym          # backend-info should not be copied
 
 proc copySym*(s: PSym; idgen: IdGenerator): PSym =
   result = newSym(s.kind, s.name, idgen, s.owner, s.info, s.options)
@@ -1992,7 +2000,7 @@ proc toVar*(typ: PType; kind: TTypeKind; idgen: IdGenerator): PType =
   ## returned. Otherwise ``typ`` is simply returned as-is.
   result = typ
   if typ.kind != kind:
-    result = newType(kind, nextTypeId(idgen), typ.owner)
+    result = newType(kind, idgen, typ.owner)
     rawAddSon(result, typ)
 
 proc toRef*(typ: PType; idgen: IdGenerator): PType =
@@ -2000,7 +2008,7 @@ proc toRef*(typ: PType; idgen: IdGenerator): PType =
   ## returned. Otherwise ``typ`` is simply returned as-is.
   result = typ
   if typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject:
-    result = newType(tyRef, nextTypeId(idgen), typ.owner)
+    result = newType(tyRef, idgen, typ.owner)
     rawAddSon(result, typ)
 
 proc toObject*(typ: PType): PType =
@@ -2108,8 +2116,8 @@ proc isSinkParam*(s: PSym): bool {.inline.} =
 proc isSinkType*(t: PType): bool {.inline.} =
   t.kind == tySink or tfHasOwned in t.flags
 
-proc newProcType*(info: TLineInfo; id: ItemId; owner: PSym): PType =
-  result = newType(tyProc, id, owner)
+proc newProcType*(info: TLineInfo; idgen: IdGenerator; owner: PSym): PType =
+  result = newType(tyProc, idgen, owner)
   result.n = newNodeI(nkFormalParams, info)
   rawAddSon(result, nil) # return type
   # result.n[0] used to be `nkType`, but now it's `nkEffectList` because
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 4103e0afb..855ec4cd9 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -663,13 +663,13 @@ proc genCppInitializer(m: BModule, prc: BProc; typ: PType): string =
   result = "{}"
   if typ.itemId in m.g.graph.initializersPerType:
     let call = m.g.graph.initializersPerType[typ.itemId]
-    if call != nil: 
+    if call != nil:
       var p = prc
       if p == nil:
         p = BProc(module: m)
       result = "{" & genCppParamsForCtor(p, call) & "}"
       if prc == nil:
-        assert p.blocks.len == 0, "BProc belongs to a struct doesnt have blocks" 
+        assert p.blocks.len == 0, "BProc belongs to a struct doesnt have blocks"
 
 proc genRecordFieldsAux(m: BModule; n: PNode,
                         rectype: PType,
@@ -1530,9 +1530,9 @@ proc genArrayInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) =
 
 proc fakeClosureType(m: BModule; owner: PSym): PType =
   # we generate the same RTTI as for a tuple[pointer, ref tuple[]]
-  result = newType(tyTuple, nextTypeId m.idgen, owner)
-  result.rawAddSon(newType(tyPointer, nextTypeId m.idgen, owner))
-  var r = newType(tyRef, nextTypeId m.idgen, owner)
+  result = newType(tyTuple, m.idgen, owner)
+  result.rawAddSon(newType(tyPointer, m.idgen, owner))
+  var r = newType(tyRef, m.idgen, owner)
   let obj = createObj(m.g.graph, m.idgen, owner, owner.info, final=false)
   r.rawAddSon(obj)
   result.rawAddSon(r)
@@ -1586,7 +1586,7 @@ proc generateRttiDestructor(g: ModuleGraph; typ: PType; owner: PSym; kind: TType
 
   dest.typ = getSysType(g, info, tyPointer)
 
-  result.typ = newProcType(info, nextTypeId(idgen), owner)
+  result.typ = newProcType(info, idgen, owner)
   result.typ.addParam dest
 
   var n = newNodeI(nkProcDef, info, bodyPos+1)
@@ -1800,9 +1800,9 @@ proc genTypeInfoV2(m: BModule; t: PType; info: TLineInfo): Rope =
   result = prefixTI.rope & result & ")".rope
 
 proc openArrayToTuple(m: BModule; t: PType): PType =
-  result = newType(tyTuple, nextTypeId m.idgen, t.owner)
-  let p = newType(tyPtr, nextTypeId m.idgen, t.owner)
-  let a = newType(tyUncheckedArray, nextTypeId m.idgen, t.owner)
+  result = newType(tyTuple, m.idgen, t.owner)
+  let p = newType(tyPtr, m.idgen, t.owner)
+  let a = newType(tyUncheckedArray, m.idgen, t.owner)
   a.add t.lastSon
   p.add a
   result.add p
diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim
index 5821988bb..2cd5f3672 100644
--- a/compiler/cgmeth.nim
+++ b/compiler/cgmeth.nim
@@ -124,7 +124,7 @@ proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
   incl(disp.flags, sfDispatcher)
   excl(disp.flags, sfExported)
   let old = disp.typ
-  disp.typ = copyType(disp.typ, nextTypeId(idgen), disp.typ.owner)
+  disp.typ = copyType(disp.typ, idgen, disp.typ.owner)
   copyTypeProps(g, idgen.module, disp.typ, old)
 
   # we can't inline the dispatcher itself (for now):
diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim
index 63e8d2fe9..4e4523601 100644
--- a/compiler/closureiters.nim
+++ b/compiler/closureiters.nim
@@ -1160,9 +1160,9 @@ proc skipThroughEmptyStates(ctx: var Ctx, n: PNode): PNode=
       n[i] = ctx.skipThroughEmptyStates(n[i])
 
 proc newArrayType(g: ModuleGraph; n: int, t: PType; idgen: IdGenerator; owner: PSym): PType =
-  result = newType(tyArray, nextTypeId(idgen), owner)
+  result = newType(tyArray, idgen, owner)
 
-  let rng = newType(tyRange, nextTypeId(idgen), owner)
+  let rng = newType(tyRange, idgen, owner)
   rng.n = newTree(nkRange, g.newIntLit(owner.info, 0), g.newIntLit(owner.info, n - 1))
   rng.rawAddSon(t)
 
diff --git a/compiler/commands.nim b/compiler/commands.nim
index e758ed09b..176b73044 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -467,6 +467,7 @@ proc parseCommand*(command: string): Command =
   of "objc", "compiletooc": cmdCompileToOC
   of "js", "compiletojs": cmdCompileToJS
   of "r": cmdCrun
+  of "m": cmdM
   of "run": cmdTcc
   of "check": cmdCheck
   of "e": cmdNimscript
diff --git a/compiler/concepts.nim b/compiler/concepts.nim
index d8b65720b..037060417 100644
--- a/compiler/concepts.nim
+++ b/compiler/concepts.nim
@@ -28,9 +28,9 @@ proc declareSelf(c: PContext; info: TLineInfo) =
   ## Adds the magical 'Self' symbols to the current scope.
   let ow = getCurrOwner(c)
   let s = newSym(skType, getIdent(c.cache, "Self"), c.idgen, ow, info)
-  s.typ = newType(tyTypeDesc, nextTypeId(c.idgen), ow)
+  s.typ = newType(tyTypeDesc, c.idgen, ow)
   s.typ.flags.incl {tfUnresolved, tfPacked}
-  s.typ.add newType(tyEmpty, nextTypeId(c.idgen), ow)
+  s.typ.add newType(tyEmpty, c.idgen, ow)
   addDecl(c, s, info)
 
 proc semConceptDecl(c: PContext; n: PNode): PNode =
diff --git a/compiler/enumtostr.nim b/compiler/enumtostr.nim
index 838cd5f97..b8d0480c7 100644
--- a/compiler/enumtostr.nim
+++ b/compiler/enumtostr.nim
@@ -14,7 +14,7 @@ proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGener
   let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
   res.typ = getSysType(g, info, tyString)
 
-  result.typ = newType(tyProc, nextTypeId idgen, t.owner)
+  result.typ = newType(tyProc, idgen, t.owner)
   result.typ.n = newNodeI(nkFormalParams, info)
   rawAddSon(result.typ, res.typ)
   result.typ.n.add newNodeI(nkEffectList, info)
@@ -76,7 +76,7 @@ proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGra
   let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
   res.typ = getSysType(g, info, tyUInt8)
 
-  result.typ = newType(tyProc, nextTypeId idgen, t.owner)
+  result.typ = newType(tyProc, idgen, t.owner)
   result.typ.n = newNodeI(nkFormalParams, info)
   rawAddSon(result.typ, res.typ)
   result.typ.n.add newNodeI(nkEffectList, info)
diff --git a/compiler/errorhandling.nim b/compiler/errorhandling.nim
index 2ad0f8806..2cde9e3fb 100644
--- a/compiler/errorhandling.nim
+++ b/compiler/errorhandling.nim
@@ -41,7 +41,8 @@ proc newError*(wrongNode: PNode; k: ErrorKind; args: varargs[PNode]): PNode =
   let innerError = errorSubNode(wrongNode)
   if innerError != nil:
     return innerError
-  result = newNodeIT(nkError, wrongNode.info, newType(tyError, ItemId(module: -1, item: -1), nil))
+  var idgen = idGeneratorForPackage(-1'i32)
+  result = newNodeIT(nkError, wrongNode.info, newType(tyError, idgen, nil))
   result.add wrongNode
   result.add newIntNode(nkIntLit, ord(k))
   for a in args: result.add a
@@ -51,7 +52,8 @@ proc newError*(wrongNode: PNode; msg: string): PNode =
   let innerError = errorSubNode(wrongNode)
   if innerError != nil:
     return innerError
-  result = newNodeIT(nkError, wrongNode.info, newType(tyError, ItemId(module: -1, item: -1), nil))
+  var idgen = idGeneratorForPackage(-1'i32)
+  result = newNodeIT(nkError, wrongNode.info, newType(tyError, idgen, nil))
   result.add wrongNode
   result.add newIntNode(nkIntLit, ord(CustomError))
   result.add newStrNode(msg, wrongNode.info)
diff --git a/compiler/guards.nim b/compiler/guards.nim
index 21c7cd045..87dbfdf6f 100644
--- a/compiler/guards.nim
+++ b/compiler/guards.nim
@@ -1098,8 +1098,8 @@ proc addFactLt*(m: var TModel; a, b: PNode) =
   addFactLe(m, a, bb)
 
 proc settype(n: PNode): PType =
-  result = newType(tySet, ItemId(module: -1, item: -1), n.typ.owner)
-  var idgen: IdGenerator = nil
+  var idgen = idGeneratorForPackage(-1'i32)
+  result = newType(tySet, idgen, n.typ.owner)
   addSonSkipIntLit(result, n.typ, idgen)
 
 proc buildOf(it, loc: PNode; o: Operators): PNode =
diff --git a/compiler/ic/bitabs.nim b/compiler/ic/bitabs.nim
index c8798e0ca..0c9994c83 100644
--- a/compiler/ic/bitabs.nim
+++ b/compiler/ic/bitabs.nim
@@ -119,6 +119,12 @@ proc load*[T](f: var RodFile; t: var BiTable[T]) =
   loadSeq(f, t.vals)
   loadSeq(f, t.keys)
 
+proc sizeOnDisc*(t: BiTable[string]): int =
+  result = 4
+  for x in t.vals:
+    result += x.len + 4
+  result += t.keys.len * sizeof(LitId)
+
 when isMainModule:
 
   var t: BiTable[string]
diff --git a/compiler/ic/cbackend.nim b/compiler/ic/cbackend.nim
index 97462f095..c2e6b08fe 100644
--- a/compiler/ic/cbackend.nim
+++ b/compiler/ic/cbackend.nim
@@ -147,12 +147,12 @@ proc generateCode*(g: ModuleGraph) =
   var alive = computeAliveSyms(g.packed, g.config)
 
   when false:
-    for i in 0..high(g.packed):
+    for i in 0..<len(g.packed):
       echo i, " is of status ", g.packed[i].status, " ", toFullPath(g.config, FileIndex(i))
 
   # First pass: Setup all the backend modules for all the modules that have
   # changed:
-  for i in 0..high(g.packed):
+  for i in 0..<len(g.packed):
     # case statement here to enforce exhaustive checks.
     case g.packed[i].status
     of undefined:
@@ -174,7 +174,7 @@ proc generateCode*(g: ModuleGraph) =
   let mainModuleIdx = g.config.projectMainIdx2.int
   # We need to generate the main module last, because only then
   # all init procs have been registered:
-  for i in 0..high(g.packed):
+  for i in 0..<len(g.packed):
     if i != mainModuleIdx:
       genPackedModule(g, i, alive)
   if mainModuleIdx >= 0:
diff --git a/compiler/ic/dce.nim b/compiler/ic/dce.nim
index 49669e4e2..6eb36431e 100644
--- a/compiler/ic/dce.nim
+++ b/compiler/ic/dce.nim
@@ -109,13 +109,13 @@ proc aliveCode(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: N
     discard "ignore non-sym atoms"
   of nkSym:
     # This symbol is alive and everything its body references.
-    followLater(c, g, c.thisModule, n.operand)
+    followLater(c, g, c.thisModule, tree[n].soperand)
   of nkModuleRef:
     let (n1, n2) = sons2(tree, n)
     assert n1.kind == nkNone
     assert n2.kind == nkNone
     let m = n1.litId
-    let item = n2.operand
+    let item = tree[n2].soperand
     let otherModule = toFileIndexCached(c.decoder, g, c.thisModule, m).int
     followLater(c, g, otherModule, item)
   of nkMacroDef, nkTemplateDef, nkTypeSection, nkTypeOfExpr,
@@ -131,7 +131,7 @@ proc aliveCode(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: N
     rangeCheckAnalysis(c, g, tree, n)
   of nkProcDef, nkConverterDef, nkMethodDef, nkFuncDef, nkIteratorDef:
     if n.firstSon.kind == nkSym and isNotGeneric(n):
-      let item = n.firstSon.operand
+      let item = tree[n.firstSon].soperand
       if isExportedToC(c, g, item):
         # This symbol is alive and everything its body references.
         followLater(c, g, c.thisModule, item)
@@ -153,7 +153,7 @@ proc computeAliveSyms*(g: PackedModuleGraph; conf: ConfigRef): AliveSyms =
   var c = AliveContext(stack: @[], decoder: PackedDecoder(config: conf),
                        thisModule: -1, alive: newSeq[IntSet](g.len),
                        options: conf.options)
-  for i in countdown(high(g), 0):
+  for i in countdown(len(g)-1, 0):
     if g[i].status != undefined:
       c.thisModule = i
       for p in allNodes(g[i].fromDisk.topLevel):
diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim
index 1b52c82b0..b244d7afb 100644
--- a/compiler/ic/ic.nim
+++ b/compiler/ic/ic.nim
@@ -7,7 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-import std/[hashes, tables, intsets]
+import std/[hashes, tables, intsets, monotimes]
 import packed_ast, bitabs, rodfiles
 import ".." / [ast, idents, lineinfos, msgs, ropes, options,
   pathutils, condsyms, packages, modulepaths]
@@ -43,8 +43,8 @@ type
     bodies*: PackedTree # other trees. Referenced from typ.n and sym.ast by their position.
     #producedGenerics*: Table[GenericKey, SymId]
     exports*: seq[(LitId, int32)]
-    hidden*: seq[(LitId, int32)]
-    reexports*: seq[(LitId, PackedItemId)]
+    hidden: seq[(LitId, int32)]
+    reexports: seq[(LitId, PackedItemId)]
     compilerProcs*: seq[(LitId, int32)]
     converters*, methods*, trmacros*, pureEnums*: seq[int32]
 
@@ -88,22 +88,22 @@ proc toString*(tree: PackedTree; pos: NodePos; m: PackedModule; nesting: int;
   of nkEmpty, nkNilLit, nkType: discard
   of nkIdent, nkStrLit..nkTripleStrLit:
     result.add " "
-    result.add m.strings[LitId tree[pos].operand]
+    result.add m.strings[LitId tree[pos].uoperand]
   of nkSym:
     result.add " "
-    result.add m.strings[m.syms[tree[pos].operand].name]
+    result.add m.strings[m.syms[tree[pos].soperand].name]
   of directIntLit:
     result.add " "
-    result.addInt tree[pos].operand
+    result.addInt tree[pos].soperand
   of externSIntLit:
     result.add " "
-    result.addInt m.numbers[LitId tree[pos].operand]
+    result.addInt m.numbers[LitId tree[pos].uoperand]
   of externUIntLit:
     result.add " "
-    result.addInt cast[uint64](m.numbers[LitId tree[pos].operand])
+    result.addInt cast[uint64](m.numbers[LitId tree[pos].uoperand])
   of nkFloatLit..nkFloat128Lit:
     result.add " "
-    result.addFloat cast[BiggestFloat](m.numbers[LitId tree[pos].operand])
+    result.addFloat cast[BiggestFloat](m.numbers[LitId tree[pos].uoperand])
   else:
     result.add "(\n"
     for i in 1..(nesting+1)*2: result.add ' '
@@ -233,10 +233,14 @@ proc addImportFileDep*(c: var PackedEncoder; m: var PackedModule; f: FileIndex)
   m.imports.add toLitId(f, c, m)
 
 proc addHidden*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
+  assert s.kind != skUnknown
   let nameId = getOrIncl(m.strings, s.name.s)
   m.hidden.add((nameId, s.itemId.item))
+  assert s.itemId.module == c.thisModule
 
 proc addExported*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
+  assert s.kind != skUnknown
+  assert s.itemId.module == c.thisModule
   let nameId = getOrIncl(m.strings, s.name.s)
   m.exports.add((nameId, s.itemId.item))
 
@@ -255,6 +259,8 @@ proc addMethod*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
   m.methods.add s.itemId.item
 
 proc addReexport*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
+  assert s.kind != skUnknown
+  if s.kind == skModule: return
   let nameId = getOrIncl(m.strings, s.name.s)
   m.reexports.add((nameId, PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m),
                                         item: s.itemId.item)))
@@ -339,7 +345,7 @@ proc storeTypeLater(t: PType; c: var PackedEncoder; m: var PackedModule): Packed
 proc storeSymLater(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId =
   if s.isNil: return nilItemId
   assert s.itemId.module >= 0
-  assert s.itemId.module >= 0
+  assert s.itemId.item >= 0
   result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item)
   if s.itemId.module == c.thisModule:
     # the sym belongs to this module, so serialize it here, eventually.
@@ -424,8 +430,13 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
 proc addModuleRef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) =
   ## add a remote symbol reference to the tree
   let info = n.info.toPackedInfo(c, m)
-  ir.addNode(kind = nkModuleRef, operand = 3.int32, # spans 3 nodes in total
-             typeId = storeTypeLater(n.typ, c, m), info = info)
+  if n.typ != n.sym.typ:
+    ir.addNode(kind = nkModuleRef, operand = 3.int32, # spans 3 nodes in total
+               info = info,
+               typeId = storeTypeLater(n.typ, c, m))
+  else:
+    ir.addNode(kind = nkModuleRef, operand = 3.int32, # spans 3 nodes in total
+              info = info)
   ir.addNode(kind = nkNone, info = info,
              operand = toLitId(n.sym.itemId.module.FileIndex, c, m).int32)
   ir.addNode(kind = nkNone, info = info,
@@ -450,8 +461,13 @@ proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var Pa
       # it is a symbol that belongs to the module we're currently
       # packing:
       let id = n.sym.storeSymLater(c, m).item
-      ir.addNode(kind = nkSym, flags = n.flags, operand = id,
-                 typeId = storeTypeLater(n.typ, c, m), info = info)
+      if n.typ != n.sym.typ:
+        ir.addNode(kind = nkSym, flags = n.flags, operand = id,
+                   info = info,
+                   typeId = storeTypeLater(n.typ, c, m))
+      else:
+        ir.addNode(kind = nkSym, flags = n.flags, operand = id,
+                   info = info)
     else:
       # store it as an external module reference:
       addModuleRef(n, ir, c, m)
@@ -565,6 +581,20 @@ proc toRodFile*(conf: ConfigRef; f: AbsoluteFile; ext = RodExt): AbsoluteFile =
   result = changeFileExt(completeGeneratedFilePath(conf,
     mangleModuleName(conf, f).AbsoluteFile), ext)
 
+const
+  BenchIC* = false
+
+when BenchIC:
+  var gloadBodies: MonoTime
+
+  template bench(x, body) =
+    let start = getMonoTime()
+    body
+    x = x + (getMonoTime() - start)
+
+else:
+  template bench(x, body) = body
+
 proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef;
                   ignoreConfig = false): RodFileError =
   var f = rodfiles.open(filename.string)
@@ -589,42 +619,45 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef
   loadTabSection stringsSection, m.strings
 
   loadSeqSection checkSumsSection, m.includes
-  if not includesIdentical(m, config):
+  if config.cmd != cmdM and not includesIdentical(m, config):
     f.err = includeFileChanged
 
   loadSeqSection depsSection, m.imports
 
-  loadTabSection numbersSection, m.numbers
+  bench gloadBodies:
+
+    loadTabSection numbersSection, m.numbers
 
-  loadSeqSection exportsSection, m.exports
-  loadSeqSection hiddenSection, m.hidden
-  loadSeqSection reexportsSection, m.reexports
+    loadSeqSection exportsSection, m.exports
+    loadSeqSection hiddenSection, m.hidden
+    loadSeqSection reexportsSection, m.reexports
 
-  loadSeqSection compilerProcsSection, m.compilerProcs
+    loadSeqSection compilerProcsSection, m.compilerProcs
 
-  loadSeqSection trmacrosSection, m.trmacros
+    loadSeqSection trmacrosSection, m.trmacros
 
-  loadSeqSection convertersSection, m.converters
-  loadSeqSection methodsSection, m.methods
-  loadSeqSection pureEnumsSection, m.pureEnums
+    loadSeqSection convertersSection, m.converters
+    loadSeqSection methodsSection, m.methods
+    loadSeqSection pureEnumsSection, m.pureEnums
 
-  loadTabSection toReplaySection, m.toReplay
-  loadTabSection topLevelSection, m.topLevel
-  loadTabSection bodiesSection, m.bodies
-  loadSeqSection symsSection, m.syms
-  loadSeqSection typesSection, m.types
+    loadTabSection toReplaySection, m.toReplay
+    loadTabSection topLevelSection, m.topLevel
 
-  loadSeqSection typeInstCacheSection, m.typeInstCache
-  loadSeqSection procInstCacheSection, m.procInstCache
-  loadSeqSection attachedOpsSection, m.attachedOps
-  loadSeqSection methodsPerTypeSection, m.methodsPerType
-  loadSeqSection enumToStringProcsSection, m.enumToStringProcs
-  loadSeqSection typeInfoSection, m.emittedTypeInfo
+    loadTabSection bodiesSection, m.bodies
+    loadSeqSection symsSection, m.syms
+    loadSeqSection typesSection, m.types
 
-  f.loadSection backendFlagsSection
-  f.loadPrim m.backendFlags
+    loadSeqSection typeInstCacheSection, m.typeInstCache
+    loadSeqSection procInstCacheSection, m.procInstCache
+    loadSeqSection attachedOpsSection, m.attachedOps
+    loadSeqSection methodsPerTypeSection, m.methodsPerType
+    loadSeqSection enumToStringProcsSection, m.enumToStringProcs
+    loadSeqSection typeInfoSection, m.emittedTypeInfo
 
-  f.loadSection sideChannelSection
+    f.loadSection backendFlagsSection
+    f.loadPrim m.backendFlags
+
+    f.loadSection sideChannelSection
   f.load m.man
 
   close(f)
@@ -736,13 +769,29 @@ type
       # PackedItemId so that it works with reexported symbols too
       # ifaceHidden includes private symbols
 
-  PackedModuleGraph* = seq[LoadedModule] # indexed by FileIndex
+type
+  PackedModuleGraph* = object
+    pm*: seq[LoadedModule] # indexed by FileIndex
+    when BenchIC:
+      depAnalysis: MonoTime
+      loadBody: MonoTime
+      loadSym, loadType, loadBodies: MonoTime
+
+when BenchIC:
+  proc echoTimes*(m: PackedModuleGraph) =
+    echo "analysis: ", m.depAnalysis, " loadBody: ", m.loadBody, " loadSym: ",
+      m.loadSym, " loadType: ", m.loadType, " all bodies: ", gloadBodies
+
+template `[]`*(m: PackedModuleGraph; i: int): LoadedModule = m.pm[i]
+template len*(m: PackedModuleGraph): int = m.pm.len
 
 proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t: PackedItemId): PType
 proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: PackedItemId): PSym
 
 proc toFileIndexCached*(c: var PackedDecoder; g: PackedModuleGraph; thisModule: int; f: LitId): FileIndex =
-  if c.lastLit == f and c.lastModule == thisModule:
+  if f == LitId(0):
+    result = InvalidFileIdx
+  elif c.lastLit == f and c.lastModule == thisModule:
     result = c.lastFile
   else:
     result = toFileIndex(f, g[thisModule].fromDisk, c.config)
@@ -769,14 +818,13 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
   result.flags = n.flags
 
   case k
-  of nkEmpty, nkNilLit, nkType:
+  of nkNone, nkEmpty, nkNilLit, nkType:
     discard
   of nkIdent:
     result.ident = getIdent(c.cache, g[thisModule].fromDisk.strings[n.litId])
   of nkSym:
-    result.sym = loadSym(c, g, thisModule, PackedItemId(module: LitId(0), item: tree[n].operand))
-  of directIntLit:
-    result.intVal = tree[n].operand
+    result.sym = loadSym(c, g, thisModule, PackedItemId(module: LitId(0), item: tree[n].soperand))
+    if result.typ == nil: result.typ = result.sym.typ
   of externIntLit:
     result.intVal = g[thisModule].fromDisk.numbers[n.litId]
   of nkStrLit..nkTripleStrLit:
@@ -788,7 +836,8 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
     assert n1.kind == nkNone
     assert n2.kind == nkNone
     transitionNoneToSym(result)
-    result.sym = loadSym(c, g, thisModule, PackedItemId(module: n1.litId, item: tree[n2].operand))
+    result.sym = loadSym(c, g, thisModule, PackedItemId(module: n1.litId, item: tree[n2].soperand))
+    if result.typ == nil: result.typ = result.sym.typ
   else:
     for n0 in sonsReadonly(tree, n):
       result.addAllowNil loadNodes(c, g, thisModule, tree, n0)
@@ -885,11 +934,22 @@ proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
   result.loc.flags = s.locFlags
   result.instantiatedFrom = loadSym(c, g, si, s.instantiatedFrom)
 
+proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
+                    fileIdx: FileIndex; cachedModules: var seq[FileIndex]): bool
+proc loadToReplayNodes(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
+                       fileIdx: FileIndex; m: var LoadedModule)
+
 proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: PackedItemId): PSym =
   if s == nilItemId:
     result = nil
   else:
     let si = moduleIndex(c, g, thisModule, s)
+    if g[si].status == undefined and c.config.cmd == cmdM:
+      var cachedModules: seq[FileIndex] = @[]
+      discard needsRecompile(g, c.config, c.cache, FileIndex(si), cachedModules)
+      for m in cachedModules:
+        loadToReplayNodes(g, c.config, c.cache, m, g[int m])
+
     assert g[si].status in {loaded, storing, stored}
     if not g[si].symsInit:
       g[si].symsInit = true
@@ -904,6 +964,7 @@ proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s:
       else:
         result = g[si].module
         assert result != nil
+        g[si].syms[s.item] = result
 
     else:
       result = g[si].syms[s.item]
@@ -948,9 +1009,11 @@ proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t
       # store it here early on, so that recursions work properly:
       g[si].types[t.item] = result
       typeBodyFromPacked(c, g, g[si].fromDisk.types[t.item], si, t.item, result)
+      #assert result.itemId.item == t.item, $(result.itemId.item, t.item)
+      assert result.itemId.item > 0, $(result.itemId.item, t.item)
     else:
       result = g[si].types[t.item]
-    assert result.itemId.item > 0
+      assert result.itemId.item > 0, "2"
 
 proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
                        fileIdx: FileIndex; m: var LoadedModule) =
@@ -1000,30 +1063,36 @@ proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache
   # Does the file belong to the fileIdx need to be recompiled?
   let m = int(fileIdx)
   if m >= g.len:
-    g.setLen(m+1)
+    g.pm.setLen(m+1)
 
   case g[m].status
   of undefined:
     g[m].status = loading
     let fullpath = msgs.toFullPath(conf, fileIdx)
     let rod = toRodFile(conf, AbsoluteFile fullpath)
-    let err = loadRodFile(rod, g[m].fromDisk, conf)
+    let err = loadRodFile(rod, g[m].fromDisk, conf, ignoreConfig = conf.cmd == cmdM)
     if err == ok:
-      result = optForceFullMake in conf.globalOptions
-      # check its dependencies:
-      for dep in g[m].fromDisk.imports:
-        let fid = toFileIndex(dep, g[m].fromDisk, conf)
-        # Warning: we need to traverse the full graph, so
-        # do **not use break here**!
-        if needsRecompile(g, conf, cache, fid, cachedModules):
-          result = true
-
-      if not result:
+      if conf.cmd == cmdM:
         setupLookupTables(g, conf, cache, fileIdx, g[m])
         cachedModules.add fileIdx
         g[m].status = loaded
+        result = false
       else:
-        g[m] = LoadedModule(status: outdated, module: g[m].module)
+        result = optForceFullMake in conf.globalOptions
+        # check its dependencies:
+        for dep in g[m].fromDisk.imports:
+          let fid = toFileIndex(dep, g[m].fromDisk, conf)
+          # Warning: we need to traverse the full graph, so
+          # do **not use break here**!
+          if needsRecompile(g, conf, cache, fid, cachedModules):
+            result = true
+
+        if not result:
+          setupLookupTables(g, conf, cache, fileIdx, g[m])
+          cachedModules.add fileIdx
+          g[m].status = loaded
+        else:
+          g.pm[m] = LoadedModule(status: outdated, module: g[m].module)
     else:
       loadError(err, rod, conf)
       g[m].status = outdated
@@ -1038,12 +1107,13 @@ proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache
 proc moduleFromRodFile*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
                         fileIdx: FileIndex; cachedModules: var seq[FileIndex]): PSym =
   ## Returns 'nil' if the module needs to be recompiled.
-  if needsRecompile(g, conf, cache, fileIdx, cachedModules):
-    result = nil
-  else:
-    result = g[int fileIdx].module
-    assert result != nil
-    assert result.position == int(fileIdx)
+  bench g.depAnalysis:
+    if needsRecompile(g, conf, cache, fileIdx, cachedModules):
+      result = nil
+    else:
+      result = g[int fileIdx].module
+      assert result != nil
+      assert result.position == int(fileIdx)
   for m in cachedModules:
     loadToReplayNodes(g, conf, cache, m, g[int m])
 
@@ -1057,46 +1127,49 @@ template setupDecoder() {.dirty.} =
 
 proc loadProcBody*(config: ConfigRef, cache: IdentCache;
                    g: var PackedModuleGraph; s: PSym): PNode =
-  let mId = s.itemId.module
-  var decoder = PackedDecoder(
-    lastModule: int32(-1),
-    lastLit: LitId(0),
-    lastFile: FileIndex(-1),
-    config: config,
-    cache: cache)
-  let pos = g[mId].fromDisk.syms[s.itemId.item].ast
-  assert pos != emptyNodeId
-  result = loadProcBody(decoder, g, mId, g[mId].fromDisk.bodies, NodePos pos)
-
-proc loadTypeFromId*(config: ConfigRef, cache: IdentCache;
-                     g: var PackedModuleGraph; module: int; id: PackedItemId): PType =
-  if id.item < g[module].types.len:
-    result = g[module].types[id.item]
-  else:
-    result = nil
-  if result == nil:
+  bench g.loadBody:
+    let mId = s.itemId.module
     var decoder = PackedDecoder(
       lastModule: int32(-1),
       lastLit: LitId(0),
       lastFile: FileIndex(-1),
       config: config,
       cache: cache)
-    result = loadType(decoder, g, module, id)
+    let pos = g[mId].fromDisk.syms[s.itemId.item].ast
+    assert pos != emptyNodeId
+    result = loadProcBody(decoder, g, mId, g[mId].fromDisk.bodies, NodePos pos)
+
+proc loadTypeFromId*(config: ConfigRef, cache: IdentCache;
+                     g: var PackedModuleGraph; module: int; id: PackedItemId): PType =
+  bench g.loadType:
+    if id.item < g[module].types.len:
+      result = g[module].types[id.item]
+    else:
+      result = nil
+    if result == nil:
+      var decoder = PackedDecoder(
+        lastModule: int32(-1),
+        lastLit: LitId(0),
+        lastFile: FileIndex(-1),
+        config: config,
+        cache: cache)
+      result = loadType(decoder, g, module, id)
 
 proc loadSymFromId*(config: ConfigRef, cache: IdentCache;
                     g: var PackedModuleGraph; module: int; id: PackedItemId): PSym =
-  if id.item < g[module].syms.len:
-    result = g[module].syms[id.item]
-  else:
-    result = nil
-  if result == nil:
-    var decoder = PackedDecoder(
-      lastModule: int32(-1),
-      lastLit: LitId(0),
-      lastFile: FileIndex(-1),
-      config: config,
-      cache: cache)
-    result = loadSym(decoder, g, module, id)
+  bench g.loadSym:
+    if id.item < g[module].syms.len:
+      result = g[module].syms[id.item]
+    else:
+      result = nil
+    if result == nil:
+      var decoder = PackedDecoder(
+        lastModule: int32(-1),
+        lastLit: LitId(0),
+        lastFile: FileIndex(-1),
+        config: config,
+        cache: cache)
+      result = loadSym(decoder, g, module, id)
 
 proc translateId*(id: PackedItemId; g: PackedModuleGraph; thisModule: int; config: ConfigRef): ItemId =
   if id.module == LitId(0):
@@ -1160,7 +1233,7 @@ proc initRodIter*(it: var RodIter; config: ConfigRef, cache: IdentCache;
     result = nil
 
 proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache;
-                         g: var PackedModuleGraph; module: FileIndex, importHidden: bool): PSym =
+                         g: var PackedModuleGraph; module: FileIndex; importHidden: bool): PSym =
   it.decoder = PackedDecoder(
     lastModule: int32(-1),
     lastLit: LitId(0),
@@ -1221,7 +1294,7 @@ proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) =
   if err != ok:
     config.quitOrRaise "Error: could not load: " & $rodfile.string & " reason: " & $err
 
-  when true:
+  when false:
     echo "exports:"
     for ex in m.exports:
       echo "  ", m.strings[ex[0]], " local ID: ", ex[1]
@@ -1237,13 +1310,32 @@ proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) =
     for ex in m.hidden:
       echo "  ", m.strings[ex[0]], " local ID: ", ex[1]
 
-  echo "all symbols"
-  for i in 0..high(m.syms):
-    if m.syms[i].name != LitId(0):
-      echo "  ", m.strings[m.syms[i].name], " local ID: ", i, " kind ", m.syms[i].kind
-    else:
-      echo "  <anon symbol?> local ID: ", i, " kind ", m.syms[i].kind
+  when false:
+    echo "all symbols"
+    for i in 0..high(m.syms):
+      if m.syms[i].name != LitId(0):
+        echo "  ", m.strings[m.syms[i].name], " local ID: ", i, " kind ", m.syms[i].kind
+      else:
+        echo "  <anon symbol?> local ID: ", i, " kind ", m.syms[i].kind
 
   echo "symbols: ", m.syms.len, " types: ", m.types.len,
     " top level nodes: ", m.topLevel.len, " other nodes: ", m.bodies.len,
     " strings: ", m.strings.len, " numbers: ", m.numbers.len
+
+  echo "SIZES:"
+  echo "symbols: ", m.syms.len * sizeof(PackedSym), " types: ", m.types.len * sizeof(PackedType),
+    " top level nodes: ", m.topLevel.len * sizeof(PackedNode),
+    " other nodes: ", m.bodies.len * sizeof(PackedNode),
+    " strings: ", sizeOnDisc(m.strings)
+  when false:
+    var tt = 0
+    var fc = 0
+    for x in m.topLevel:
+      if x.kind == nkSym or x.typeId == nilItemId: inc tt
+      if x.flags == {}: inc fc
+    for x in m.bodies:
+      if x.kind == nkSym or x.typeId == nilItemId: inc tt
+      if x.flags == {}: inc fc
+    let total = float(m.topLevel.len + m.bodies.len)
+    echo "nodes with nil type: ", tt, " in % ", tt.float / total
+    echo "nodes with empty flags: ", fc.float / total
diff --git a/compiler/ic/integrity.nim b/compiler/ic/integrity.nim
index 00014f15a..0ffd87c2f 100644
--- a/compiler/ic/integrity.nim
+++ b/compiler/ic/integrity.nim
@@ -72,15 +72,16 @@ proc checkForeignSym(c: var CheckedContext; symId: PackedItemId) =
     c.thisModule = oldThisModule
 
 proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) =
-  if tree[n].typeId != nilItemId:
-    checkType(c, tree[n].typeId)
+  let t = findType(tree, n)
+  if t != nilItemId:
+    checkType(c, t)
   case n.kind
   of nkEmpty, nkNilLit, nkType, nkNilRodNode:
     discard
   of nkIdent:
     assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId
   of nkSym:
-    checkLocalSym(c, tree[n].operand)
+    checkLocalSym(c, tree[n].soperand)
   of directIntLit:
     discard
   of externIntLit, nkFloatLit..nkFloat128Lit:
@@ -91,7 +92,7 @@ proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) =
     let (n1, n2) = sons2(tree, n)
     assert n1.kind == nkNone
     assert n2.kind == nkNone
-    checkForeignSym(c, PackedItemId(module: n1.litId, item: tree[n2].operand))
+    checkForeignSym(c, PackedItemId(module: n1.litId, item: tree[n2].soperand))
   else:
     for n0 in sonsReadonly(tree, n):
       checkNode(c, tree, n0)
@@ -140,7 +141,7 @@ proc checkModule(c: var CheckedContext; m: PackedModule) =
 
 proc checkIntegrity*(g: ModuleGraph) =
   var c = CheckedContext(g: g)
-  for i in 0..high(g.packed):
+  for i in 0..<len(g.packed):
     # case statement here to enforce exhaustive checks.
     case g.packed[i].status
     of undefined:
@@ -150,4 +151,3 @@ proc checkIntegrity*(g: ModuleGraph) =
     of stored, storing, outdated, loaded:
       c.thisModule = int32 i
       checkModule(c, g.packed[i].fromDisk)
-
diff --git a/compiler/ic/navigator.nim b/compiler/ic/navigator.nim
index c2d7ee4ad..da8e7e597 100644
--- a/compiler/ic/navigator.nim
+++ b/compiler/ic/navigator.nim
@@ -63,7 +63,7 @@ proc search(c: var NavContext; tree: PackedTree): ItemId =
     let i = NodePos(i)
     case tree[i].kind
     of nkSym:
-      let item = tree[i].operand
+      let item = tree[i].soperand
       if searchLocalSym(c, c.g.packed[c.thisModule].fromDisk.syms[item], tree[i].info):
         return ItemId(module: c.thisModule, item: item)
     of nkModuleRef:
@@ -72,7 +72,7 @@ proc search(c: var NavContext; tree: PackedTree): ItemId =
         let (n1, n2) = sons2(tree, i)
         assert n1.kind == nkInt32Lit
         assert n2.kind == nkInt32Lit
-        let pId = PackedItemId(module: n1.litId, item: tree[n2].operand)
+        let pId = PackedItemId(module: n1.litId, item: tree[n2].soperand)
         let itemId = translateId(pId, c.g.packed, c.thisModule, c.g.config)
         if searchForeignSym(c, itemId, tree[i].info):
           return itemId
@@ -101,21 +101,21 @@ proc list(c: var NavContext; tree: PackedTree; sym: ItemId) =
     let i = NodePos(i)
     case tree[i].kind
     of nkSym:
-      let item = tree[i].operand
+      let item = tree[i].soperand
       if sym.item == item and sym.module == c.thisModule:
         usage(c, tree[i].info, isDecl(tree, parent(i)))
     of nkModuleRef:
       let (n1, n2) = sons2(tree, i)
       assert n1.kind == nkNone
       assert n2.kind == nkNone
-      let pId = PackedItemId(module: n1.litId, item: tree[n2].operand)
+      let pId = PackedItemId(module: n1.litId, item: tree[n2].soperand)
       let itemId = translateId(pId, c.g.packed, c.thisModule, c.g.config)
       if itemId.item == sym.item and sym.module == itemId.module:
         usage(c, tree[i].info, isDecl(tree, parent(i)))
     else: discard
 
 proc searchForIncludeFile(g: ModuleGraph; fullPath: string): int =
-  for i in 0..high(g.packed):
+  for i in 0..<len(g.packed):
     for k in 1..high(g.packed[i].fromDisk.includes):
       # we start from 1 because the first "include" file is
       # the module's filename.
@@ -158,7 +158,7 @@ proc nav(g: ModuleGraph) =
     localError(g.config, unpacked, "no symbol at this position")
     return
 
-  for i in 0..high(g.packed):
+  for i in 0..<len(g.packed):
     # case statement here to enforce exhaustive checks.
     case g.packed[i].status
     of undefined:
@@ -175,7 +175,7 @@ proc navUsages*(g: ModuleGraph) = nav(g)
 proc navDefusages*(g: ModuleGraph) = nav(g)
 
 proc writeRodFiles*(g: ModuleGraph) =
-  for i in 0..high(g.packed):
+  for i in 0..<len(g.packed):
     case g.packed[i].status
     of undefined, loading, stored, loaded:
       discard "nothing to do"
diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim
index ea7c7f967..8971d72be 100644
--- a/compiler/ic/packed_ast.nim
+++ b/compiler/ic/packed_ast.nim
@@ -33,7 +33,7 @@ type
     item*: int32         # same as the in-memory representation
 
 const
-  nilItemId* = PackedItemId(module: LitId(0), item: -1.int32)
+  nilItemId* = PackedItemId(module: LitId(0), item: 0.int32)
 
 const
   emptyNodeId* = NodeId(-1)
@@ -87,25 +87,35 @@ type
     typeInst*: PackedItemId
     nonUniqueId*: int32
 
-  PackedNode* = object     # 28 bytes
-    kind*: TNodeKind
-    flags*: TNodeFlags
-    operand*: int32  # for kind in {nkSym, nkSymDef}: SymId
-                     # for kind in {nkStrLit, nkIdent, nkNumberLit}: LitId
-                     # for kind in nkNone: direct value
-                     # for non-atom kinds: the number of nodes (for easy skipping)
-    typeId*: PackedItemId
+  PackedNode* = object     # 8 bytes
+    x: uint32
     info*: PackedLineInfo
 
   PackedTree* = object ## usually represents a full Nim module
     nodes: seq[PackedNode]
-    #withFlags: seq[(int, TNodeFlags)]
-    #withTypes: seq[(int, PackedItemId)]
+    withFlags: seq[(int32, TNodeFlags)]
+    withTypes: seq[(int32, PackedItemId)]
 
   PackedInstantiation* = object
     key*, sym*: PackedItemId
     concreteTypes*: seq[PackedItemId]
 
+const
+  NodeKindBits = 8'u32
+  NodeKindMask = (1'u32 shl NodeKindBits) - 1'u32
+
+template kind*(n: PackedNode): TNodeKind = TNodeKind(n.x and NodeKindMask)
+template uoperand*(n: PackedNode): uint32 = (n.x shr NodeKindBits)
+template soperand*(n: PackedNode): int32 = int32(uoperand(n))
+
+template toX(k: TNodeKind; operand: uint32): uint32 =
+  uint32(k) or (operand shl NodeKindBits)
+
+template toX(k: TNodeKind; operand: LitId): uint32 =
+  uint32(k) or (operand.uint32 shl NodeKindBits)
+
+template typeId*(n: PackedNode): PackedItemId = n.typ
+
 proc `==`*(a, b: SymId): bool {.borrow.}
 proc hash*(a: SymId): Hash {.borrow.}
 
@@ -118,16 +128,13 @@ proc newTreeFrom*(old: PackedTree): PackedTree =
   when false: result.sh = old.sh
 
 proc addIdent*(tree: var PackedTree; s: LitId; info: PackedLineInfo) =
-  tree.nodes.add PackedNode(kind: nkIdent, operand: int32(s), info: info)
+  tree.nodes.add PackedNode(x: toX(nkIdent, uint32(s)), info: info)
 
 proc addSym*(tree: var PackedTree; s: int32; info: PackedLineInfo) =
-  tree.nodes.add PackedNode(kind: nkSym, operand: s, info: info)
-
-proc addModuleId*(tree: var PackedTree; s: ModuleId; info: PackedLineInfo) =
-  tree.nodes.add PackedNode(kind: nkNone, operand: int32(s), info: info)
+  tree.nodes.add PackedNode(x: toX(nkSym, cast[uint32](s)), info: info)
 
 proc addSymDef*(tree: var PackedTree; s: SymId; info: PackedLineInfo) =
-  tree.nodes.add PackedNode(kind: nkSym, operand: int32(s), info: info)
+  tree.nodes.add PackedNode(x: toX(nkSym, cast[uint32](s)), info: info)
 
 proc isAtom*(tree: PackedTree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= nkNilLit
 
@@ -137,8 +144,11 @@ type
 proc addNode*(t: var PackedTree; kind: TNodeKind; operand: int32;
               typeId: PackedItemId = nilItemId; info: PackedLineInfo;
               flags: TNodeFlags = {}) =
-  t.nodes.add PackedNode(kind: kind, flags: flags, operand: operand,
-                         typeId: typeId, info: info)
+  t.nodes.add PackedNode(x: toX(kind, cast[uint32](operand)), info: info)
+  if flags != {}:
+    t.withFlags.add (t.nodes.len.int32 - 1, flags)
+  if typeId != nilItemId:
+    t.withTypes.add (t.nodes.len.int32 - 1, typeId)
 
 proc prepare*(tree: var PackedTree; kind: TNodeKind; flags: TNodeFlags; typeId: PackedItemId; info: PackedLineInfo): PatchPos =
   result = PatchPos tree.nodes.len
@@ -150,26 +160,30 @@ proc prepare*(dest: var PackedTree; source: PackedTree; sourcePos: NodePos): Pat
 
 proc patch*(tree: var PackedTree; pos: PatchPos) =
   let pos = pos.int
-  assert tree.nodes[pos].kind > nkNilLit
+  let k = tree.nodes[pos].kind
+  assert k > nkNilLit
   let distance = int32(tree.nodes.len - pos)
-  tree.nodes[pos].operand = distance
+  assert distance > 0
+  tree.nodes[pos].x = toX(k, cast[uint32](distance))
 
 proc len*(tree: PackedTree): int {.inline.} = tree.nodes.len
 
 proc `[]`*(tree: PackedTree; i: NodePos): lent PackedNode {.inline.} =
   tree.nodes[i.int]
 
+template rawSpan(n: PackedNode): int = int(uoperand(n))
+
 proc nextChild(tree: PackedTree; pos: var int) {.inline.} =
   if tree.nodes[pos].kind > nkNilLit:
-    assert tree.nodes[pos].operand > 0
-    inc pos, tree.nodes[pos].operand
+    assert tree.nodes[pos].uoperand > 0
+    inc pos, tree.nodes[pos].rawSpan
   else:
     inc pos
 
 iterator sonsReadonly*(tree: PackedTree; n: NodePos): NodePos =
   var pos = n.int
   assert tree.nodes[pos].kind > nkNilLit
-  let last = pos + tree.nodes[pos].operand
+  let last = pos + tree.nodes[pos].rawSpan
   inc pos
   while pos < last:
     yield NodePos pos
@@ -190,7 +204,7 @@ iterator isons*(dest: var PackedTree; tree: PackedTree;
 iterator sonsFrom1*(tree: PackedTree; n: NodePos): NodePos =
   var pos = n.int
   assert tree.nodes[pos].kind > nkNilLit
-  let last = pos + tree.nodes[pos].operand
+  let last = pos + tree.nodes[pos].rawSpan
   inc pos
   if pos < last:
     nextChild tree, pos
@@ -204,7 +218,7 @@ iterator sonsWithoutLast2*(tree: PackedTree; n: NodePos): NodePos =
     inc count
   var pos = n.int
   assert tree.nodes[pos].kind > nkNilLit
-  let last = pos + tree.nodes[pos].operand
+  let last = pos + tree.nodes[pos].rawSpan
   inc pos
   while pos < last and count > 2:
     yield NodePos pos
@@ -214,7 +228,7 @@ iterator sonsWithoutLast2*(tree: PackedTree; n: NodePos): NodePos =
 proc parentImpl(tree: PackedTree; n: NodePos): NodePos =
   # finding the parent of a node is rather easy:
   var pos = n.int - 1
-  while pos >= 0 and (isAtom(tree, pos) or (pos + tree.nodes[pos].operand - 1 < n.int)):
+  while pos >= 0 and (isAtom(tree, pos) or (pos + tree.nodes[pos].rawSpan - 1 < n.int)):
     dec pos
   #assert pos >= 0, "node has no parent"
   result = NodePos(pos)
@@ -240,20 +254,32 @@ proc firstSon*(tree: PackedTree; n: NodePos): NodePos {.inline.} =
 proc kind*(tree: PackedTree; n: NodePos): TNodeKind {.inline.} =
   tree.nodes[n.int].kind
 proc litId*(tree: PackedTree; n: NodePos): LitId {.inline.} =
-  LitId tree.nodes[n.int].operand
+  LitId tree.nodes[n.int].uoperand
 proc info*(tree: PackedTree; n: NodePos): PackedLineInfo {.inline.} =
   tree.nodes[n.int].info
 
+proc findType*(tree: PackedTree; n: NodePos): PackedItemId =
+  for x in tree.withTypes:
+    if x[0] == int32(n): return x[1]
+    if x[0] > int32(n): return nilItemId
+  return nilItemId
+
+proc findFlags*(tree: PackedTree; n: NodePos): TNodeFlags =
+  for x in tree.withFlags:
+    if x[0] == int32(n): return x[1]
+    if x[0] > int32(n): return {}
+  return {}
+
 template typ*(n: NodePos): PackedItemId =
-  tree.nodes[n.int].typeId
+  tree.findType(n)
 template flags*(n: NodePos): TNodeFlags =
-  tree.nodes[n.int].flags
+  tree.findFlags(n)
 
-template operand*(n: NodePos): int32 =
-  tree.nodes[n.int].operand
+template uoperand*(n: NodePos): uint32 =
+  tree.nodes[n.int].uoperand
 
 proc span*(tree: PackedTree; pos: int): int {.inline.} =
-  if isAtom(tree, pos): 1 else: tree.nodes[pos].operand
+  if isAtom(tree, pos): 1 else: tree.nodes[pos].rawSpan
 
 proc sons2*(tree: PackedTree; n: NodePos): (NodePos, NodePos) =
   assert(not isAtom(tree, n.int))
@@ -283,38 +309,12 @@ when false:
 
 template kind*(n: NodePos): TNodeKind = tree.nodes[n.int].kind
 template info*(n: NodePos): PackedLineInfo = tree.nodes[n.int].info
-template litId*(n: NodePos): LitId = LitId tree.nodes[n.int].operand
+template litId*(n: NodePos): LitId = LitId tree.nodes[n.int].uoperand
 
-template symId*(n: NodePos): SymId = SymId tree.nodes[n.int].operand
+template symId*(n: NodePos): SymId = SymId tree.nodes[n.int].soperand
 
 proc firstSon*(n: NodePos): NodePos {.inline.} = NodePos(n.int+1)
 
-when false:
-  # xxx `nkStrLit` or `nkStrLit..nkTripleStrLit:` below?
-  proc strLit*(tree: PackedTree; n: NodePos): lent string =
-    assert n.kind == nkStrLit
-    result = tree.sh.strings[LitId tree.nodes[n.int].operand]
-
-  proc strVal*(tree: PackedTree; n: NodePos): string =
-    assert n.kind == nkStrLit
-    result = tree.sh.strings[LitId tree.nodes[n.int].operand]
-    #result = cookedStrLit(raw)
-
-  proc filenameVal*(tree: PackedTree; n: NodePos): string =
-    case n.kind
-    of nkStrLit:
-      result = strVal(tree, n)
-    of nkIdent:
-      result = tree.sh.strings[n.litId]
-    of nkSym:
-      result = tree.sh.strings[tree.sh.syms[int n.symId].name]
-    else:
-      result = ""
-
-  proc identAsStr*(tree: PackedTree; n: NodePos): lent string =
-    assert n.kind == nkIdent
-    result = tree.sh.strings[LitId tree.nodes[n.int].operand]
-
 const
   externIntLit* = {nkCharLit,
     nkIntLit,
@@ -332,17 +332,6 @@ const
   externUIntLit* = {nkUIntLit, nkUInt8Lit, nkUInt16Lit, nkUInt32Lit, nkUInt64Lit}
   directIntLit* = nkNone
 
-when false:
-  proc identIdImpl(tree: PackedTree; n: NodePos): LitId =
-    if n.kind == nkIdent:
-      result = n.litId
-    elif n.kind == nkSym:
-      result = tree.sh.syms[int n.symId].name
-    else:
-      result = LitId(0)
-
-  template identId*(n: NodePos): LitId = identIdImpl(tree, n)
-
 template copyInto*(dest, n, body) =
   let patchPos = prepare(dest, tree, n)
   body
@@ -353,28 +342,8 @@ template copyIntoKind*(dest, kind, info, body) =
   body
   patch dest, patchPos
 
-when false:
-  proc hasPragma*(tree: PackedTree; n: NodePos; pragma: string): bool =
-    let litId = tree.sh.strings.getKeyId(pragma)
-    if litId == LitId(0):
-      return false
-    assert n.kind == nkPragma
-    for ch0 in sonsReadonly(tree, n):
-      if ch0.kind == nkExprColonExpr:
-        if ch0.firstSon.identId == litId:
-          return true
-      elif ch0.identId == litId:
-        return true
-
 proc getNodeId*(tree: PackedTree): NodeId {.inline.} = NodeId tree.nodes.len
 
-when false:
-  proc produceError*(dest: var PackedTree; tree: PackedTree; n: NodePos; msg: string) =
-    let patchPos = prepare(dest, nkError, n.info)
-    dest.add nkStrLit, msg, n.info
-    copyTree(dest, tree, n)
-    patch dest, patchPos
-
 iterator allNodes*(tree: PackedTree): NodePos =
   var p = 0
   while p < tree.len:
@@ -387,6 +356,10 @@ proc toPackedItemId*(item: int32): PackedItemId {.inline.} =
 
 proc load*(f: var RodFile; t: var PackedTree) =
   loadSeq f, t.nodes
+  loadSeq f, t.withFlags
+  loadSeq f, t.withTypes
 
 proc store*(f: var RodFile; t: PackedTree) =
   storeSeq f, t.nodes
+  storeSeq f, t.withFlags
+  storeSeq f, t.withTypes
diff --git a/compiler/importer.nim b/compiler/importer.nim
index ff1f9f63e..a8de1e8bc 100644
--- a/compiler/importer.nim
+++ b/compiler/importer.nim
@@ -230,7 +230,7 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym; im
   else:
     for i in 0..n.safeLen-1:
       importForwarded(c, n[i], exceptSet, fromMod, importSet)
-    
+
 proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool): PSym =
   result = realModule
   template createModuleAliasImpl(ident): untyped =
@@ -313,6 +313,7 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym =
     result = nil
 
 proc afterImport(c: PContext, m: PSym) =
+  if isCachedModule(c.graph, m): return
   # fixes bug #17510, for re-exported symbols
   let realModuleId = c.importModuleMap[m.id]
   for s in allSyms(c.graph, m):
diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim
index a278f7c49..4870ca1a3 100644
--- a/compiler/injectdestructors.nim
+++ b/compiler/injectdestructors.nim
@@ -214,7 +214,7 @@ proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string; inferredFr
   localError(c.graph.config, ri.info, errGenerated, m)
 
 proc makePtrType(c: var Con, baseType: PType): PType =
-  result = newType(tyPtr, nextTypeId c.idgen, c.owner)
+  result = newType(tyPtr, c.idgen, c.owner)
   addSonSkipIntLit(result, baseType, c.idgen)
 
 proc genOp(c: var Con; op: PSym; dest: PNode): PNode =
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index 248effcaf..9345ac114 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -135,10 +135,10 @@ proc createClosureIterStateType*(g: ModuleGraph; iter: PSym; idgen: IdGenerator)
   var n = newNodeI(nkRange, iter.info)
   n.add newIntNode(nkIntLit, -1)
   n.add newIntNode(nkIntLit, 0)
-  result = newType(tyRange, nextTypeId(idgen), iter)
+  result = newType(tyRange, idgen, iter)
   result.n = n
   var intType = nilOrSysInt(g)
-  if intType.isNil: intType = newType(tyInt, nextTypeId(idgen), iter)
+  if intType.isNil: intType = newType(tyInt, idgen, iter)
   rawAddSon(result, intType)
 
 proc createStateField(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym =
@@ -342,7 +342,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym;
                         info: TLineInfo): PType =
   result = c.ownerToType.getOrDefault(owner.id)
   if result.isNil:
-    result = newType(tyRef, nextTypeId(c.idgen), owner)
+    result = newType(tyRef, c.idgen, owner)
     let obj = createEnvObj(c.graph, c.idgen, owner, info)
     rawAddSon(result, obj)
     c.ownerToType[owner.id] = result
@@ -350,7 +350,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym;
 proc asOwnedRef(c: var DetectionPass; t: PType): PType =
   if optOwnedRefs in c.graph.config.globalOptions:
     assert t.kind == tyRef
-    result = newType(tyOwned, nextTypeId(c.idgen), t.owner)
+    result = newType(tyOwned, c.idgen, t.owner)
     result.flags.incl tfHasOwned
     result.rawAddSon t
   else:
@@ -359,7 +359,7 @@ proc asOwnedRef(c: var DetectionPass; t: PType): PType =
 proc getEnvTypeForOwnerUp(c: var DetectionPass; owner: PSym;
                           info: TLineInfo): PType =
   var r = c.getEnvTypeForOwner(owner, info)
-  result = newType(tyPtr, nextTypeId(c.idgen), owner)
+  result = newType(tyPtr, c.idgen, owner)
   rawAddSon(result, r.skipTypes({tyOwned, tyRef, tyPtr}))
 
 proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim
index ea0d6e6f8..8995e1073 100644
--- a/compiler/liftdestructors.nim
+++ b/compiler/liftdestructors.nim
@@ -1057,7 +1057,7 @@ proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttache
   res.typ = typ
   src.typ = typ
 
-  result.typ = newType(tyProc, nextTypeId idgen, owner)
+  result.typ = newType(tyProc, idgen, owner)
   result.typ.n = newNodeI(nkFormalParams, info)
   rawAddSon(result.typ, res.typ)
   result.typ.n.add newNodeI(nkEffectList, info)
@@ -1102,7 +1102,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
   else:
     src.typ = typ
 
-  result.typ = newProcType(info, nextTypeId(idgen), owner)
+  result.typ = newProcType(info, idgen, owner)
   result.typ.addParam dest
   if kind notin {attachedDestructor, attachedWasMoved}:
     result.typ.addParam src
diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim
index 42d0f1790..f8ae67f41 100644
--- a/compiler/lowerings.nim
+++ b/compiler/lowerings.nim
@@ -144,7 +144,7 @@ proc lowerSwap*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNod
   result.add newFastAsgnStmt(n[2], tempAsNode)
 
 proc createObj*(g: ModuleGraph; idgen: IdGenerator; owner: PSym, info: TLineInfo; final=true): PType =
-  result = newType(tyObject, nextTypeId(idgen), owner)
+  result = newType(tyObject, idgen, owner)
   if final:
     rawAddSon(result, nil)
     incl result.flags, tfFinal
@@ -320,7 +320,7 @@ proc indirectAccess*(a, b: PSym, info: TLineInfo): PNode =
 proc genAddrOf*(n: PNode; idgen: IdGenerator; typeKind = tyPtr): PNode =
   result = newNodeI(nkAddr, n.info, 1)
   result[0] = n
-  result.typ = newType(typeKind, nextTypeId(idgen), n.typ.owner)
+  result.typ = newType(typeKind, idgen, n.typ.owner)
   result.typ.rawAddSon(n.typ)
 
 proc genDeref*(n: PNode; k = nkHiddenDeref): PNode =
diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim
index 63fe0369c..dcde49bff 100644
--- a/compiler/magicsys.nim
+++ b/compiler/magicsys.nim
@@ -18,7 +18,7 @@ export createMagic
 proc nilOrSysInt*(g: ModuleGraph): PType = g.sysTypes[tyInt]
 
 proc newSysType(g: ModuleGraph; kind: TTypeKind, size: int): PType =
-  result = newType(kind, nextTypeId(g.idgen), g.systemModule)
+  result = newType(kind, g.idgen, g.systemModule)
   result.size = size
   result.align = size.int16
 
@@ -27,7 +27,7 @@ proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym =
   if result == nil:
     localError(g.config, info, "system module needs: " & name)
     result = newSym(skError, getIdent(g.cache, name), g.idgen, g.systemModule, g.systemModule.info, {})
-    result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule)
+    result.typ = newType(tyError, g.idgen, g.systemModule)
 
 proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym =
   result = nil
@@ -40,7 +40,7 @@ proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSy
   if result != nil: return result
   localError(g.config, info, "system module needs: " & name)
   result = newSym(skError, id, g.idgen, g.systemModule, g.systemModule.info, {})
-  result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule)
+  result.typ = newType(tyError, g.idgen, g.systemModule)
 
 proc sysTypeFromName*(g: ModuleGraph; info: TLineInfo; name: string): PType =
   result = getSysSym(g, info, name).typ
@@ -93,7 +93,7 @@ proc getFloatLitType*(g: ModuleGraph; literal: PNode): PType =
 
 proc skipIntLit*(t: PType; id: IdGenerator): PType {.inline.} =
   if t.n != nil and t.kind in {tyInt, tyFloat}:
-    result = copyType(t, nextTypeId(id), t.owner)
+    result = copyType(t, id, t.owner)
     result.n = nil
   else:
     result = t
@@ -151,7 +151,7 @@ proc getMagicEqSymForType*(g: ModuleGraph; t: PType; info: TLineInfo): PSym =
       "can't find magic equals operator for type kind " & $t.kind)
 
 proc makePtrType*(baseType: PType; idgen: IdGenerator): PType =
-  result = newType(tyPtr, nextTypeId idgen, baseType.owner)
+  result = newType(tyPtr, idgen, baseType.owner)
   addSonSkipIntLit(result, baseType, idgen)
 
 proc makeAddr*(n: PNode; idgen: IdGenerator): PNode =
diff --git a/compiler/main.nim b/compiler/main.nim
index 6651128eb..d9c3baa09 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -28,8 +28,7 @@ import nir / nir
 when defined(nimPreviewSlimSystem):
   import std/[syncio, assertions]
 
-import ic / [cbackend, integrity, navigator]
-from ic / ic import rodViewer
+import ic / [cbackend, integrity, navigator, ic]
 
 import ../dist/checksums/src/checksums/sha1
 
@@ -335,7 +334,10 @@ proc mainCommand*(graph: ModuleGraph) =
 
   ## process all commands
   case conf.cmd
-  of cmdBackends: compileToBackend()
+  of cmdBackends:
+    compileToBackend()
+    when BenchIC:
+      echoTimes graph.packed
   of cmdTcc:
     when hasTinyCBackend:
       extccomp.setCC(conf, "tcc", unknownLineInfo)
@@ -431,6 +433,10 @@ proc mainCommand*(graph: ModuleGraph) =
       for it in conf.searchPaths: msgWriteln(conf, it.string)
   of cmdCheck:
     commandCheck(graph)
+  of cmdM:
+    graph.config.symbolFiles = v2Sf
+    setUseIc(graph.config.symbolFiles != disabledSf)
+    commandCheck(graph)
   of cmdParse:
     wantMainModule(conf)
     discard parseFile(conf.projectMainIdx, cache, conf)
diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim
index 5c23325e8..99175815b 100644
--- a/compiler/modulegraphs.nim
+++ b/compiler/modulegraphs.nim
@@ -212,10 +212,10 @@ proc strTableAdds*(g: ModuleGraph, m: PSym, s: PSym) =
 proc isCachedModule(g: ModuleGraph; module: int): bool {.inline.} =
   result = module < g.packed.len and g.packed[module].status == loaded
 
-proc isCachedModule(g: ModuleGraph; m: PSym): bool {.inline.} =
+proc isCachedModule*(g: ModuleGraph; m: PSym): bool {.inline.} =
   isCachedModule(g, m.position)
 
-proc simulateCachedModule*(g: ModuleGraph; moduleSym: PSym; m: PackedModule) =
+proc simulateCachedModule(g: ModuleGraph; moduleSym: PSym; m: PackedModule) =
   when false:
     echo "simulating ", moduleSym.name.s, " ", moduleSym.position
   simulateLoadedModule(g.packed, g.config, g.cache, moduleSym, m)
@@ -378,7 +378,7 @@ proc loadCompilerProc*(g: ModuleGraph; name: string): PSym =
   if g.config.symbolFiles == disabledSf: return nil
 
   # slow, linear search, but the results are cached:
-  for module in 0..high(g.packed):
+  for module in 0..<len(g.packed):
     #if isCachedModule(g, module):
     let x = searchForCompilerproc(g.packed[module], name)
     if x >= 0:
@@ -435,7 +435,7 @@ proc registerModule*(g: ModuleGraph; m: PSym) =
     setLen(g.ifaces, m.position + 1)
 
   if m.position >= g.packed.len:
-    setLen(g.packed, m.position + 1)
+    setLen(g.packed.pm, m.position + 1)
 
   g.ifaces[m.position] = Iface(module: m, converters: @[], patterns: @[],
                                uniqueName: rope(uniqueModuleName(g.config, FileIndex(m.position))))
diff --git a/compiler/nilcheck.nim b/compiler/nilcheck.nim
index 1713a888f..2a6de8733 100644
--- a/compiler/nilcheck.nim
+++ b/compiler/nilcheck.nim
@@ -918,7 +918,7 @@ proc infix(ctx: NilCheckerContext, l: PNode, r: PNode, magic: TMagic): PNode =
     newSymNode(op, r.info),
     l,
     r)
-  result.typ = newType(tyBool, nextTypeId ctx.idgen, nil)
+  result.typ = newType(tyBool, ctx.idgen, nil)
 
 proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode =
   var cache = newIdentCache()
@@ -928,7 +928,7 @@ proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode =
   result = nkPrefix.newTree(
     newSymNode(op, node.info),
     node)
-  result.typ = newType(tyBool, nextTypeId ctx.idgen, nil)
+  result.typ = newType(tyBool, ctx.idgen, nil)
 
 proc infixEq(ctx: NilCheckerContext, l: PNode, r: PNode): PNode =
   infix(ctx, l, r, mEqRef)
diff --git a/compiler/options.nim b/compiler/options.nim
index 704248d78..e50acbf49 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -150,6 +150,7 @@ type
     cmdCrun # compile and run in nimache
     cmdTcc # run the project via TCC backend
     cmdCheck # semantic checking for whole project
+    cmdM     # only compile a single
     cmdParse # parse a single file (for debugging)
     cmdRod # .rod to some text representation (for debugging)
     cmdIdeTools # ide tools (e.g. nimsuggest)
@@ -819,16 +820,17 @@ proc getNimcacheDir*(conf: ConfigRef): AbsoluteDir =
     else: "_d"
 
   # XXX projectName should always be without a file extension!
-  result = if not conf.nimcacheDir.isEmpty:
-             conf.nimcacheDir
-           elif conf.backend == backendJs:
-             if conf.outDir.isEmpty:
-               conf.projectPath / genSubDir
-             else:
-               conf.outDir / genSubDir
-           else:
-            AbsoluteDir(getOsCacheDir() / splitFile(conf.projectName).name &
-               nimcacheSuffix(conf))
+  result =
+    if not conf.nimcacheDir.isEmpty:
+      conf.nimcacheDir
+    elif conf.backend == backendJs:
+      if conf.outDir.isEmpty:
+        conf.projectPath / genSubDir
+      else:
+        conf.outDir / genSubDir
+    else:
+      AbsoluteDir(getOsCacheDir() / splitFile(conf.projectName).name &
+        nimcacheSuffix(conf))
 
 proc pathSubs*(conf: ConfigRef; p, config: string): string =
   let home = removeTrailingDirSep(os.getHomeDir())
diff --git a/compiler/passes.nim b/compiler/passes.nim
index 87a9d05c8..d6b141078 100644
--- a/compiler/passes.nim
+++ b/compiler/passes.nim
@@ -165,13 +165,13 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fr
 
   template processModuleAux(moduleStatus) =
     onProcessing(graph, fileIdx, moduleStatus, fromModule = fromModule)
-    var s: PLLStream
+    var s: PLLStream = nil
     if sfMainModule in flags:
       if graph.config.projectIsStdin: s = stdin.llStreamOpen
       elif graph.config.projectIsCmd: s = llStreamOpen(graph.config.cmdInput)
     discard processModule(graph, result, idGeneratorFromModule(result), s)
   if result == nil:
-    var cachedModules: seq[FileIndex]
+    var cachedModules: seq[FileIndex] = @[]
     result = moduleFromRodFile(graph, fileIdx, cachedModules)
     let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
     if result == nil:
@@ -185,7 +185,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fr
       partialInitModule(result, graph, fileIdx, filename)
     for m in cachedModules:
       registerModuleById(graph, m)
-      replayStateChanges(graph.packed[m.int].module, graph)
+      replayStateChanges(graph.packed.pm[m.int].module, graph)
       replayGenericCacheInformation(graph, m.int)
   elif graph.isDirty(result):
     result.flags.excl sfDirty
diff --git a/compiler/pipelines.nim b/compiler/pipelines.nim
index 8f40ac031..c3b7a8b7e 100644
--- a/compiler/pipelines.nim
+++ b/compiler/pipelines.nim
@@ -228,7 +228,7 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
     closeRodFile(graph, module)
   result = true
 
-proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fromModule: PSym = nil): PSym =
+proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags; fromModule: PSym = nil): PSym =
   var flags = flags
   if fileIdx == graph.config.projectMainIdx2: flags.incl sfMainModule
   result = graph.getModule(fileIdx)
@@ -252,10 +252,14 @@ proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymF
     else:
       if sfSystemModule in flags:
         graph.systemModule = result
+      if sfMainModule in flags and graph.config.cmd == cmdM:
+        result.flags.incl flags
+        registerModule(graph, result)
+        processModuleAux("import")
       partialInitModule(result, graph, fileIdx, filename)
     for m in cachedModules:
       registerModuleById(graph, m)
-      replayStateChanges(graph.packed[m.int].module, graph)
+      replayStateChanges(graph.packed.pm[m.int].module, graph)
       replayGenericCacheInformation(graph, m.int)
   elif graph.isDirty(result):
     result.flags.excl sfDirty
diff --git a/compiler/plugins/itersgen.nim b/compiler/plugins/itersgen.nim
index 1a291c04d..c5e9dc853 100644
--- a/compiler/plugins/itersgen.nim
+++ b/compiler/plugins/itersgen.nim
@@ -32,7 +32,7 @@ proc iterToProcImpl*(c: PContext, n: PNode): PNode =
   let body = liftIterToProc(c.graph, iter.sym, getBody(c.graph, iter.sym), t, c.idgen)
 
   let prc = newSym(skProc, n[3].ident, c.idgen, iter.sym.owner, iter.sym.info)
-  prc.typ = copyType(iter.sym.typ, nextTypeId c.idgen, prc)
+  prc.typ = copyType(iter.sym.typ, c.idgen, prc)
   excl prc.typ.flags, tfCapturesEnv
   prc.typ.n.add newSymNode(getEnvParam(iter.sym))
   prc.typ.rawAddSon t
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 1908b5a0d..568db0d0f 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -145,8 +145,8 @@ proc commonType*(c: PContext; x, y: PType): PType =
     # turn any concrete typedesc into the abstract typedesc type
     if a.len == 0: result = a
     else:
-      result = newType(tyTypeDesc, nextTypeId(c.idgen), a.owner)
-      rawAddSon(result, newType(tyNone, nextTypeId(c.idgen), a.owner))
+      result = newType(tyTypeDesc, c.idgen, a.owner)
+      rawAddSon(result, newType(tyNone, c.idgen, a.owner))
   elif b.kind in {tyArray, tySet, tySequence} and
       a.kind == b.kind:
     # check for seq[empty] vs. seq[int]
@@ -159,7 +159,7 @@ proc commonType*(c: PContext; x, y: PType): PType =
       let bEmpty = isEmptyContainer(b[i])
       if aEmpty != bEmpty:
         if nt.isNil:
-          nt = copyType(a, nextTypeId(c.idgen), a.owner)
+          nt = copyType(a, c.idgen, a.owner)
           copyTypeProps(c.graph, c.idgen.module, nt, a)
 
         nt[i] = if aEmpty: b[i] else: a[i]
@@ -206,7 +206,7 @@ proc commonType*(c: PContext; x, y: PType): PType =
       # ill-formed AST, no need for additional tyRef/tyPtr
       if k != tyNone and x.kind != tyGenericInst:
         let r = result
-        result = newType(k, nextTypeId(c.idgen), r.owner)
+        result = newType(k, c.idgen, r.owner)
         result.addSonSkipIntLit(r, c.idgen)
 
 proc endsInNoReturn(n: PNode): bool =
@@ -638,7 +638,7 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool, ch
           result.add newTree(nkExprColonExpr, recNode, asgnExpr)
           return
 
-      let asgnType = newType(tyTypeDesc, nextTypeId(c.idgen), recNode.typ.owner)
+      let asgnType = newType(tyTypeDesc, c.idgen, recNode.typ.owner)
       rawAddSon(asgnType, recNode.typ)
       let asgnExpr = newTree(nkCall,
                       newSymNode(getSysMagic(c.graph, recNode.info, "zeroDefault", mZeroDefault)),
@@ -744,8 +744,8 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
 proc preparePContext*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PContext =
   result = newContext(graph, module)
   result.idgen = idgen
-  result.enforceVoidContext = newType(tyTyped, nextTypeId(idgen), nil)
-  result.voidType = newType(tyVoid, nextTypeId(idgen), nil)
+  result.enforceVoidContext = newType(tyTyped, idgen, nil)
+  result.voidType = newType(tyVoid, idgen, nil)
 
   if result.p != nil: internalError(graph.config, module.info, "sem.preparePContext")
   result.semConstExpr = semConstExpr
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 91b15d5c7..a24fa4fb5 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -182,12 +182,12 @@ proc getIntLitType*(c: PContext; literal: PNode): PType =
     result = c.intTypeCache[value.int]
     if result == nil:
       let ti = getSysType(c.graph, literal.info, tyInt)
-      result = copyType(ti, nextTypeId(c.idgen), ti.owner)
+      result = copyType(ti, c.idgen, ti.owner)
       result.n = literal
       c.intTypeCache[value.int] = result
   else:
     let ti = getSysType(c.graph, literal.info, tyInt)
-    result = copyType(ti, nextTypeId(c.idgen), ti.owner)
+    result = copyType(ti, c.idgen, ti.owner)
     result.n = literal
 
 proc setIntLitType*(c: PContext; result: PNode) =
@@ -220,12 +220,11 @@ proc setIntLitType*(c: PContext; result: PNode) =
     internalError(c.config, result.info, "invalid int size")
 
 proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
-  result.genericSym = s
-  result.inst = inst
+  result = TInstantiationPair(genericSym: s, inst: inst)
 
 proc filename*(c: PContext): string =
   # the module's filename
-  return toFilename(c.config, FileIndex c.module.position)
+  result = toFilename(c.config, FileIndex c.module.position)
 
 proc scopeDepth*(c: PContext): int {.inline.} =
   result = if c.currentScope != nil: c.currentScope.depthLevel
@@ -328,7 +327,8 @@ proc newContext*(graph: ModuleGraph; module: PSym): PContext =
   result.features = graph.config.features
   if graph.config.symbolFiles != disabledSf:
     let id = module.position
-    assert graph.packed[id].status in {undefined, outdated}
+    if graph.config.cmd != cmdM:
+      assert graph.packed[id].status in {undefined, outdated}
     graph.packed[id].status = storing
     graph.packed[id].module = module
     initEncoder graph, module
@@ -397,10 +397,10 @@ proc addToLib*(lib: PLib, sym: PSym) =
   sym.annex = lib
 
 proc newTypeS*(kind: TTypeKind, c: PContext, sons: seq[PType] = @[]): PType =
-  result = newType(kind, nextTypeId(c.idgen), getCurrOwner(c), sons = sons)
+  result = newType(kind, c.idgen, getCurrOwner(c), sons = sons)
 
 proc makePtrType*(owner: PSym, baseType: PType; idgen: IdGenerator): PType =
-  result = newType(tyPtr, nextTypeId(idgen), owner)
+  result = newType(tyPtr, idgen, owner)
   addSonSkipIntLit(result, baseType, idgen)
 
 proc makePtrType*(c: PContext, baseType: PType): PType =
@@ -428,7 +428,7 @@ proc makeVarType*(owner: PSym, baseType: PType; idgen: IdGenerator; kind = tyVar
   if baseType.kind == kind:
     result = baseType
   else:
-    result = newType(kind, nextTypeId(idgen), owner)
+    result = newType(kind, idgen, owner)
     addSonSkipIntLit(result, baseType, idgen)
 
 proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
@@ -447,15 +447,15 @@ proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
 
 proc newTypeWithSons*(owner: PSym, kind: TTypeKind, sons: seq[PType];
                       idgen: IdGenerator): PType =
-  result = newType(kind, nextTypeId(idgen), owner, sons = sons)
+  result = newType(kind, idgen, owner, sons = sons)
 
 proc newTypeWithSons*(c: PContext, kind: TTypeKind,
                       sons: seq[PType]): PType =
-  result = newType(kind, nextTypeId(c.idgen), getCurrOwner(c), sons = sons)
+  result = newType(kind, c.idgen, getCurrOwner(c), sons = sons)
 
 proc newTypeWithSons*(c: PContext, kind: TTypeKind,
                       parent: PType): PType =
-  result = newType(kind, nextTypeId(c.idgen), getCurrOwner(c), parent = parent)
+  result = newType(kind, c.idgen, getCurrOwner(c), parent = parent)
 
 proc makeStaticExpr*(c: PContext, n: PNode): PNode =
   result = newNodeI(nkStaticExpr, n.info)
@@ -471,7 +471,7 @@ proc makeAndType*(c: PContext, t1, t2: PType): PType =
   result.flags.incl tfHasMeta
 
 proc makeOrType*(c: PContext, t1, t2: PType): PType =
-  
+
   if t1.kind != tyOr and t2.kind != tyOr:
     result = newTypeS(tyOr, c, sons = @[t1, t2])
   else:
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 28d2647fd..b7fac6046 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1827,7 +1827,7 @@ proc goodLineInfo(arg: PNode): TLineInfo =
 
 proc makeTupleAssignments(c: PContext; n: PNode): PNode =
   ## expand tuple unpacking assignment into series of assignments
-  ## 
+  ##
   ## mirrored with semstmts.makeVarTupleSection
   let lhs = n[0]
   let value = semExprWithType(c, n[1], {efTypeAllowed})
@@ -2384,7 +2384,7 @@ proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
     result = semDirectOp(c, n, flags)
 
 proc createFlowVar(c: PContext; t: PType; info: TLineInfo): PType =
-  result = newType(tyGenericInvocation, nextTypeId c.idgen, c.module)
+  result = newType(tyGenericInvocation, c.idgen, c.module)
   addSonSkipIntLit(result, magicsys.getCompilerProc(c.graph, "FlowVar").typ, c.idgen)
   addSonSkipIntLit(result, t, c.idgen)
   result = instGenericContainer(c, info, result, allowMetaTypes = false)
@@ -2538,7 +2538,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags; expectedType: P
         let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
         expected.kind in {tySequence, tyOpenArray}):
       # seq type inference
-      var arrayType = newType(tyOpenArray, nextTypeId(c.idgen), expected.owner)
+      var arrayType = newType(tyOpenArray, c.idgen, expected.owner)
       arrayType.rawAddSon(expected[0])
       if n[0].kind == nkSym and sfFromGeneric in n[0].sym.flags:
         # may have been resolved to `@`[empty] at some point,
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index e722f932f..faa609584 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -23,13 +23,13 @@ when defined(nimPreviewSlimSystem):
 
 proc errorType*(g: ModuleGraph): PType =
   ## creates a type representing an error state
-  result = newType(tyError, nextTypeId(g.idgen), g.owners[^1])
+  result = newType(tyError, g.idgen, g.owners[^1])
   result.flags.incl tfCheckedForDestructor
 
 proc getIntLitTypeG(g: ModuleGraph; literal: PNode; idgen: IdGenerator): PType =
   # we cache some common integer literal types for performance:
   let ti = getSysType(g, literal.info, tyInt)
-  result = copyType(ti, nextTypeId(idgen), ti.owner)
+  result = copyType(ti, idgen, ti.owner)
   result.n = literal
 
 proc newIntNodeT*(intVal: Int128, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
@@ -513,7 +513,7 @@ proc foldConStrStr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
 proc newSymNodeTypeDesc*(s: PSym; idgen: IdGenerator; info: TLineInfo): PNode =
   result = newSymNode(s, info)
   if s.typ.kind != tyTypeDesc:
-    result.typ = newType(tyTypeDesc, idgen.nextTypeId, s.owner)
+    result.typ = newType(tyTypeDesc, idgen, s.owner)
     result.typ.addSonSkipIntLit(s.typ, idgen)
   else:
     result.typ = s.typ
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 6f2ddd95a..548b922fe 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -136,7 +136,7 @@ proc uninstantiate(t: PType): PType =
     else: t
 
 proc getTypeDescNode(c: PContext; typ: PType, sym: PSym, info: TLineInfo): PNode =
-  var resType = newType(tyTypeDesc, nextTypeId c.idgen, sym)
+  var resType = newType(tyTypeDesc, c.idgen, sym)
   rawAddSon(resType, typ)
   result = toNode(resType, info)
 
@@ -177,7 +177,7 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
     result.info = traitCall.info
   of "arity":
     result = newIntNode(nkIntLit, operand.len - ord(operand.kind==tyProc))
-    result.typ = newType(tyInt, nextTypeId c.idgen, context)
+    result.typ = newType(tyInt, c.idgen, context)
     result.info = traitCall.info
   of "genericHead":
     var arg = operand
@@ -189,7 +189,7 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
     #   result = toNode(resType, traitCall.info) # doesn't work yet
     else:
       localError(c.config, traitCall.info, "expected generic type, got: type $2 of kind $1" % [arg.kind.toHumanStr, typeToString(operand)])
-      result = newType(tyError, nextTypeId c.idgen, context).toNode(traitCall.info)
+      result = newType(tyError, c.idgen, context).toNode(traitCall.info)
   of "stripGenericParams":
     result = uninstantiate(operand).toNode(traitCall.info)
   of "supportsCopyMem":
@@ -387,7 +387,7 @@ proc semUnown(c: PContext; n: PNode): PNode =
         elems[i] = unownedType(c, t[i])
         if elems[i] != t[i]: someChange = true
       if someChange:
-        result = newType(tyTuple, nextTypeId c.idgen, t.owner)
+        result = newType(tyTuple, c.idgen, t.owner)
         # we have to use 'rawAddSon' here so that type flags are
         # properly computed:
         for e in elems: result.rawAddSon(e)
@@ -398,7 +398,7 @@ proc semUnown(c: PContext; n: PNode): PNode =
        tyGenericInst, tyAlias:
       let b = unownedType(c, t[^1])
       if b != t[^1]:
-        result = copyType(t, nextTypeId c.idgen, t.owner)
+        result = copyType(t, c.idgen, t.owner)
         copyTypeProps(c.graph, c.idgen.module, result, t)
 
         result[^1] = b
@@ -441,7 +441,7 @@ proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym
   # proc body:
   result.ast = transform(c, orig.ast, origParamType, newParamType, oldParam, newParam)
   # proc signature:
-  result.typ = newProcType(result.info, nextTypeId c.idgen, result)
+  result.typ = newProcType(result.info, c.idgen, result)
   result.typ.addParam newParam
 
 proc semQuantifier(c: PContext; n: PNode): PNode =
diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim
index 33278af2f..37c939bcd 100644
--- a/compiler/semobjconstr.nim
+++ b/compiler/semobjconstr.nim
@@ -180,7 +180,7 @@ proc collectOrAddMissingCaseFields(c: PContext, branchNode: PNode,
                           constrCtx: var ObjConstrContext, defaults: var seq[PNode]) =
   let res = collectMissingCaseFields(c, branchNode, constrCtx, defaults)
   for sym in res:
-    let asgnType = newType(tyTypeDesc, nextTypeId(c.idgen), sym.typ.owner)
+    let asgnType = newType(tyTypeDesc, c.idgen, sym.typ.owner)
     let recTyp = sym.typ.skipTypes(defaultFieldsSkipTypes)
     rawAddSon(asgnType, recTyp)
     let asgnExpr = newTree(nkCall,
diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim
index af77a1972..d5fc72760 100644
--- a/compiler/semparallel.nim
+++ b/compiler/semparallel.nim
@@ -405,7 +405,7 @@ proc transformSlices(g: ModuleGraph; idgen: IdGenerator; n: PNode): PNode =
     let op = n[0].sym
     if op.name.s == "[]" and op.fromSystem:
       result = copyNode(n)
-      var typ = newType(tyOpenArray, nextTypeId(g.idgen), result.typ.owner)
+      var typ = newType(tyOpenArray, idgen, result.typ.owner)
       typ.add result.typ[0]
       result.typ = typ
       let opSlice = newSymNode(createMagic(g, idgen, "slice", mSlice))
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 336c80c20..48447c0eb 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -603,7 +603,7 @@ const
 
 proc makeVarTupleSection(c: PContext, n, a, def: PNode, typ: PType, symkind: TSymKind, origResult: var PNode): PNode =
   ## expand tuple unpacking assignments into new var/let/const section
-  ## 
+  ##
   ## mirrored with semexprs.makeTupleAssignments
   if typ.kind != tyTuple:
     localError(c.config, a.info, errTupleUnpackingTupleExpected %
@@ -1499,7 +1499,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
         localError(c.config, name.info, "{.exportc.} not allowed for type aliases")
       elif s.typ.kind == tyGenericBody:
         localError(c.config, name.info, "{.exportc.} not allowed for generic types")
-    
+
     if tfBorrowDot in s.typ.flags:
       let body = s.typ.skipTypes({tyGenericBody})
       if body.kind != tyDistinct:
@@ -2076,7 +2076,7 @@ proc finishMethod(c: PContext, s: PSym) =
   if hasObjParam(s):
     methodDef(c.graph, c.idgen, s)
 
-proc semCppMember(c: PContext; s: PSym; n: PNode) = 
+proc semCppMember(c: PContext; s: PSym; n: PNode) =
   if sfImportc notin s.flags:
     let isVirtual = sfVirtual in s.flags
     let isCtor = sfConstructor in s.flags
@@ -2107,7 +2107,7 @@ proc semCppMember(c: PContext; s: PSym; n: PNode) =
           pragmaName & " procs must be defined in the same scope as the type they are virtual for and it must be a top level scope")
     else:
       localError(c.config, n.info, pragmaName & " procs are only supported in C++")
-  else: 
+  else:
     var typ = s.typ[0]
     if typ != nil and typ.kind == tyObject and typ.itemId notin c.graph.initializersPerType:
       var initializerCall = newTree(nkCall, newSymNode(s))
@@ -2344,7 +2344,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
 
   if sfCppMember * s.flags != {}:
     semCppMember(c, s, n)
-          
+
   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 c.config.ideCmd in {ideSug, ideCon} and s.kind notin {skMacro, skTemplate} and not
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 0a0050f2f..ebbf75e35 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -42,7 +42,8 @@ proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext, sons: seq[PType]):
   if prev == nil or prev.kind == tyGenericBody:
     result = newTypeS(kind, c, sons = sons)
   else:
-    result = newType(prev, sons)
+    result = prev
+    result.setSons(sons)
     if result.kind == tyForward: result.kind = kind
   #if kind == tyError: result.flags.incl tfCheckedForDestructor
 
@@ -927,7 +928,7 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType
               sfSystemModule notin c.module.flags:
             message(c.config, n.info, warnInheritFromException, "")
           if not tryAddInheritedFields(c, check, pos, concreteBase, n):
-            return newType(tyError, nextTypeId c.idgen, result.owner)
+            return newType(tyError, c.idgen, result.owner)
 
       elif concreteBase.kind == tyForward:
         c.skipTypes.add n #we retry in the final pass
@@ -949,7 +950,7 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType
   else:
     # partial object so add things to the check
     if not tryAddInheritedFields(c, check, pos, result, n, isPartial = true):
-      return newType(tyError, nextTypeId c.idgen, result.owner)
+      return newType(tyError, c.idgen, result.owner)
 
   semRecordNodeAux(c, n[2], check, pos, result.n, result)
   if n[0].kind != nkEmpty:
@@ -1189,7 +1190,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
   of tyGenericInst:
     result = nil
     if paramType.lastSon.kind == tyUserTypeClass:
-      var cp = copyType(paramType, nextTypeId c.idgen, getCurrOwner(c))
+      var cp = copyType(paramType, c.idgen, getCurrOwner(c))
       copyTypeProps(c.graph, c.idgen.module, cp, paramType)
 
       cp.kind = tyUserTypeClassInst
@@ -1229,7 +1230,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
   of tyUserTypeClasses, tyBuiltInTypeClass, tyCompositeTypeClass,
      tyAnd, tyOr, tyNot, tyConcept:
     result = addImplicitGeneric(c,
-        copyType(paramType, nextTypeId c.idgen, getCurrOwner(c)), paramTypId,
+        copyType(paramType, c.idgen, getCurrOwner(c)), paramTypId,
         info, genericParams, paramName)
 
   of tyGenericParam:
@@ -1385,7 +1386,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       let finalType = if lifted != nil: lifted else: typ.skipIntLit(c.idgen)
       arg.typ = finalType
       arg.position = counter
-      if constraint != nil: 
+      if constraint != nil:
         #only replace the constraint when it has been set as arg could contain codegenDecl
         arg.constraint = constraint
       inc(counter)
@@ -1398,7 +1399,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       onDef(a[j].info, arg)
       a[j] = newSymNode(arg)
 
-  var r: PType = 
+  var r: PType =
     if n[0].kind != nkEmpty:
       semTypeNode(c, n[0], nil)
     else:
@@ -1514,7 +1515,7 @@ proc trySemObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType): b
   var newf = newNodeI(nkRecList, n.info)
   semRecordNodeAux(c, t.n, check, pos, newf, t)
 
-proc containsGenericInvocationWithForward(n: PNode): bool = 
+proc containsGenericInvocationWithForward(n: PNode): bool =
   if n.kind == nkSym and n.sym.ast != nil and n.sym.ast.len > 1 and n.sym.ast[2].kind == nkObjectTy:
     for p in n.sym.ast[2][^1]:
       if p.kind == nkIdentDefs and p[1].typ != nil and p[1].typ.kind == tyGenericInvocation and
@@ -1535,7 +1536,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
   addSonSkipIntLit(result, t, c.idgen)
 
   template addToResult(typ, skip) =
-    
+
     if typ.isNil:
       internalAssert c.config, false
       rawAddSon(result, typ)
@@ -1655,7 +1656,7 @@ proc semTypeExpr(c: PContext, n: PNode; prev: PType): PType =
 
 proc freshType(c: PContext; res, prev: PType): PType {.inline.} =
   if prev.isNil or prev.kind == tyGenericBody:
-    result = copyType(res, nextTypeId c.idgen, res.owner)
+    result = copyType(res, c.idgen, res.owner)
     copyTypeProps(c.graph, c.idgen.module, result, res)
   else:
     result = res
@@ -2046,7 +2047,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
       result = semTypeNode(c, n[0], nil)
       if result != nil:
         let old = result
-        result = copyType(result, nextTypeId c.idgen, getCurrOwner(c))
+        result = copyType(result, c.idgen, getCurrOwner(c))
         copyTypeProps(c.graph, c.idgen.module, result, old)
         for i in 1..<n.len:
           result.rawAddSon(semTypeNode(c, n[i], nil))
@@ -2340,7 +2341,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
         if j == 0:
           finalType = typ
         else:
-          finalType = copyType(typ, nextTypeId c.idgen, typ.owner)
+          finalType = copyType(typ, c.idgen, typ.owner)
           copyTypeProps(c.graph, c.idgen.module, finalType, typ)
         # it's important the we create an unique
         # type for each generic param. the index
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 4ab0e2de1..bb664c71f 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -327,7 +327,7 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
   if cl.allowMetaTypes:
     result = t.exactReplica
   else:
-    result = copyType(t, nextTypeId(cl.c.idgen), t.owner)
+    result = copyType(t, cl.c.idgen, t.owner)
     copyTypeProps(cl.c.graph, cl.c.idgen.module, result, t)
     #cl.typeMap.topLayer.idTablePut(result, t)
 
@@ -383,7 +383,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
   else:
     header = instCopyType(cl, t)
 
-  result = newType(tyGenericInst, nextTypeId(cl.c.idgen), t[0].owner, sons = @[header[0]])
+  result = newType(tyGenericInst, cl.c.idgen, t[0].owner, sons = @[header[0]])
   result.flags = header.flags
   # be careful not to propagate unnecessary flags here (don't use rawAddSon)
   # ugh need another pass for deeply recursive generic types (e.g. PActor)
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 77f8de68b..aa7a72dd9 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -764,7 +764,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
         of tyStatic:
           param = paramSym skConst
           param.typ = typ.exactReplica
-          #copyType(typ, nextTypeId(c.idgen), typ.owner)
+          #copyType(typ, c.idgen, typ.owner)
           if typ.n == nil:
             param.typ.flags.incl tfInferrableStatic
           else:
@@ -772,7 +772,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
         of tyUnknown:
           param = paramSym skVar
           param.typ = typ.exactReplica
-          #copyType(typ, nextTypeId(c.idgen), typ.owner)
+          #copyType(typ, c.idgen, typ.owner)
         else:
           param = paramSym skType
           param.typ = if typ.isMetaType:
@@ -824,7 +824,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
     result = generateTypeInstance(c, m.bindings, typeClass.sym.info, ff)
   else:
     result = ff.exactReplica
-    #copyType(ff, nextTypeId(c.idgen), ff.owner)
+    #copyType(ff, c.idgen, ff.owner)
 
   result.n = checkedBody
 
@@ -1642,7 +1642,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
       var depth = -1
       if fobj != nil and aobj != nil and askip == fskip:
         depth = isObjectSubtype(c, aobj, fobj, f)
-      
+
       if result == isNone:
         # Here object inheriting from generic/specialized generic object
         # crossing path with metatypes/aliases, so we need to separate them
@@ -1949,7 +1949,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
     let reevaluated = tryResolvingStaticExpr(c, f.n)
     if reevaluated == nil:
       result = isNone
-      return 
+      return
     case reevaluated.typ.kind
     of tyTypeDesc:
       result = typeRel(c, a, reevaluated.typ.base, flags)
diff --git a/compiler/sinkparameter_inference.nim b/compiler/sinkparameter_inference.nim
index aa53e7429..09d54ec79 100644
--- a/compiler/sinkparameter_inference.nim
+++ b/compiler/sinkparameter_inference.nim
@@ -31,7 +31,7 @@ proc checkForSink*(config: ConfigRef; idgen: IdGenerator; owner: PSym; arg: PNod
       if sfWasForwarded notin owner.flags:
         let argType = arg.sym.typ
 
-        let sinkType = newType(tySink, nextTypeId(idgen), owner)
+        let sinkType = newType(tySink, idgen, owner)
         sinkType.size = argType.size
         sinkType.align = argType.align
         sinkType.paddingAtEnd = argType.paddingAtEnd
diff --git a/compiler/spawn.nim b/compiler/spawn.nim
index e6c089966..bfcdd78ea 100644
--- a/compiler/spawn.nim
+++ b/compiler/spawn.nim
@@ -169,7 +169,7 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
   params.add threadParam.newSymNode
   params.add argsParam.newSymNode
 
-  var t = newType(tyProc, nextTypeId idgen, threadParam.owner)
+  var t = newType(tyProc, idgen, threadParam.owner)
   t.rawAddSon nil
   t.rawAddSon threadParam.typ
   t.rawAddSon argsParam.typ
@@ -189,7 +189,7 @@ proc createCastExpr(argsParam: PSym; objType: PType; idgen: IdGenerator): PNode
   result = newNodeI(nkCast, argsParam.info)
   result.add newNodeI(nkEmpty, argsParam.info)
   result.add newSymNode(argsParam)
-  result.typ = newType(tyPtr, nextTypeId idgen, objType.owner)
+  result.typ = newType(tyPtr, idgen, objType.owner)
   result.typ.rawAddSon(objType)
 
 template checkMagicProcs(g: ModuleGraph, n: PNode, formal: PNode) =
@@ -395,7 +395,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp
 
   var barrierAsExpr: PNode = nil
   if barrier != nil:
-    let typ = newType(tyPtr, nextTypeId idgen, owner)
+    let typ = newType(tyPtr, idgen, owner)
     typ.rawAddSon(magicsys.getCompilerProc(g, "Barrier").typ)
     var field = newSym(skField, getIdent(g.cache, "barrier"), idgen, owner, n.info, g.config.options)
     field.typ = typ
@@ -417,7 +417,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp
 
   elif spawnKind == srByVar:
     var field = newSym(skField, getIdent(g.cache, "fv"), idgen, owner, n.info, g.config.options)
-    field.typ = newType(tyPtr, nextTypeId idgen, objType.owner)
+    field.typ = newType(tyPtr, idgen, objType.owner)
     field.typ.rawAddSon(retType)
     discard objType.addField(field, g.cache, idgen)
     fvAsExpr = indirectAccess(castExpr, field, n.info)
diff --git a/compiler/types.nim b/compiler/types.nim
index b9c69d871..7bb29405f 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -1451,7 +1451,7 @@ proc baseOfDistinct*(t: PType; g: ModuleGraph; idgen: IdGenerator): PType =
   if t.kind == tyDistinct:
     result = t[0]
   else:
-    result = copyType(t, nextTypeId idgen, t.owner)
+    result = copyType(t, idgen, t.owner)
     copyTypeProps(g, idgen.module, result, t)
     var parent: PType = nil
     var it = result
@@ -1635,7 +1635,7 @@ proc takeType*(formal, arg: PType; g: ModuleGraph; idgen: IdGenerator): PType =
     result = formal
   elif formal.kind in {tyOpenArray, tyVarargs, tySequence} and
       arg.isEmptyContainer:
-    let a = copyType(arg.skipTypes({tyGenericInst, tyAlias}), nextTypeId(idgen), arg.owner)
+    let a = copyType(arg.skipTypes({tyGenericInst, tyAlias}), idgen, arg.owner)
     copyTypeProps(g, idgen.module, a, arg)
     a[ord(arg.kind == tyArray)] = formal[0]
     result = a
diff --git a/compiler/vm.nim b/compiler/vm.nim
index fd03c4bae..8824eca37 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -540,7 +540,7 @@ template takeAddress(reg, source) =
   GC_ref source
 
 proc takeCharAddress(c: PCtx, src: PNode, index: BiggestInt, pc: int): TFullReg =
-  let typ = newType(tyPtr, nextTypeId c.idgen, c.module.owner)
+  let typ = newType(tyPtr, c.idgen, c.module.owner)
   typ.add getSysType(c.graph, c.debug[pc], tyChar)
   var node = newNodeIT(nkIntLit, c.debug[pc], typ) # xxx nkPtrLit
   node.intVal = cast[int](src.strVal[index].addr)
@@ -2444,7 +2444,7 @@ const evalMacroLimit = 1000
 
 #proc errorNode(idgen: IdGenerator; owner: PSym, n: PNode): PNode =
 #  result = newNodeI(nkEmpty, n.info)
-#  result.typ = newType(tyError, nextTypeId idgen, owner)
+#  result.typ = newType(tyError, idgen, owner)
 #  result.typ.flags.incl tfCheckedForDestructor
 
 proc evalMacroCall*(module: PSym; idgen: IdGenerator; g: ModuleGraph; templInstCounter: ref int;
diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim
index 18f9fe5ca..ed3ca68ac 100644
--- a/compiler/vmdeps.nim
+++ b/compiler/vmdeps.nim
@@ -51,9 +51,9 @@ proc mapTypeToBracketX(cache: IdentCache; name: string; m: TMagic; t: PType; inf
   result.add atomicTypeX(cache, name, m, t, info, idgen)
   for i in 0..<t.len:
     if t[i] == nil:
-      let void = atomicTypeX(cache, "void", mVoid, t, info, idgen)
-      void.typ = newType(tyVoid, nextTypeId(idgen), t.owner)
-      result.add void
+      let voidt = atomicTypeX(cache, "void", mVoid, t, info, idgen)
+      voidt.typ = newType(tyVoid, idgen, t.owner)
+      result.add voidt
     else:
       result.add mapTypeToAstX(cache, t[i], info, idgen, inst)