summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim3
-rw-r--r--compiler/ic/packed_ast.nim31
-rw-r--r--compiler/ic/to_packed_ast.nim160
-rw-r--r--compiler/magicsys.nim50
-rw-r--r--compiler/modulegraphs.nim12
-rw-r--r--compiler/sem.nim2
-rw-r--r--compiler/semdata.nim54
-rw-r--r--compiler/semexprs.nim18
-rw-r--r--compiler/semfold.nim200
-rw-r--r--compiler/semmagic.nim8
-rw-r--r--compiler/semstmts.nim2
-rw-r--r--compiler/semtypes.nim4
-rw-r--r--compiler/semtypinst.nim18
-rw-r--r--compiler/transf.nim4
14 files changed, 289 insertions, 277 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index f8e8f1d3b..0c075cb12 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -223,6 +223,7 @@ type
     nkTupleConstr         # a tuple constructor
     nkModuleRef           # for .rod file support: A (moduleId, itemId) pair
     nkReplayAction        # for .rod file support: A replay action
+    nkNilRodNode          # for .rod file support: a 'nil' PNode
 
   TNodeKinds* = set[TNodeKind]
 
@@ -923,7 +924,7 @@ type
     typeInst*: PType          # for generic instantiations the tyGenericInst that led to this
                               # type.
     uniqueId*: ItemId         # due to a design mistake, we need to keep the real ID here as it
-                              # required by the --incremental:on mode.
+                              # is required by the --incremental:on mode.
 
   TPair* = object
     key*, val*: RootRef
diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim
index 0758d3b98..708761764 100644
--- a/compiler/ic/packed_ast.nim
+++ b/compiler/ic/packed_ast.nim
@@ -12,7 +12,7 @@
 ## use this representation directly in all the transformations,
 ## it is superior.
 
-import std / [hashes, tables, strtabs, md5]
+import std / [hashes, tables, strtabs]
 import bitabs
 import ".." / [ast, options]
 
@@ -27,8 +27,6 @@ type
     module*: LitId       # 0 if it's this module
     item*: int32         # same as the in-memory representation
 
-  TypeId* = PackedItemId
-
 const
   nilItemId* = PackedItemId(module: LitId(0), item: -1.int32)
 
@@ -51,7 +49,7 @@ type
   PackedSym* = object
     kind*: TSymKind
     name*: LitId
-    typ*: TypeId
+    typ*: PackedItemId
     flags*: TSymFlags
     magic*: TMagic
     info*: PackedLineInfo
@@ -74,7 +72,7 @@ type
     callConv*: TCallingConvention
     #nodekind*: TNodeKind
     flags*: TTypeFlags
-    types*: seq[TypeId]
+    types*: seq[PackedItemId]
     n*: NodeId
     methods*: seq[(int, PackedItemId)]
     #nodeflags*: TNodeFlags
@@ -86,7 +84,7 @@ type
     paddingAtEnd*: int16
     lockLevel*: TLockLevel # lock level as required for deadlock checking
     # not serialized: loc*: TLoc because it is backend-specific
-    typeInst*: TypeId
+    typeInst*: PackedItemId
     nonUniqueId*: int32
 
   PackedNode* = object     # 20 bytes
@@ -96,17 +94,9 @@ type
                      # for kind in {nkStrLit, nkIdent, nkNumberLit}: LitId
                      # for kind in nkInt32Lit: direct value
                      # for non-atom kinds: the number of nodes (for easy skipping)
-    typeId*: TypeId
+    typeId*: PackedItemId
     info*: PackedLineInfo
 
-  ModulePhase* = enum
-    preLookup, lookedUpTopLevelStmts
-
-  GenericKey* = object
-    module*: int32
-    name*: string
-    types*: seq[MD5Digest] # is this a joke?
-
   PackedTree* = object ## usually represents a full Nim module
     nodes*: seq[PackedNode]
     #sh*: Shared
@@ -121,18 +111,11 @@ type
     floats*: BiTable[BiggestFloat]
     #config*: ConfigRef
 
-proc hash*(key: GenericKey): Hash =
-  var h: Hash = 0
-  h = h !& hash(key.module)
-  h = h !& hash(key.name)
-  h = h !& hash(key.types)
-  result = !$h
-
 proc `==`*(a, b: SymId): bool {.borrow.}
 proc hash*(a: SymId): Hash {.borrow.}
 
 proc `==`*(a, b: NodePos): bool {.borrow.}
-#proc `==`*(a, b: TypeId): bool {.borrow.}
+#proc `==`*(a, b: PackedItemId): bool {.borrow.}
 proc `==`*(a, b: NodeId): bool {.borrow.}
 
 proc newTreeFrom*(old: PackedTree): PackedTree =
@@ -197,7 +180,7 @@ when false:
     result = PatchPos tree.nodes.len
     tree.nodes.add PackedNode(kind: kind, operand: 0, info: info)
 
-proc prepare*(tree: var PackedTree; kind: TNodeKind; flags: TNodeFlags; typeId: TypeId; info: PackedLineInfo): PatchPos =
+proc prepare*(tree: var PackedTree; kind: TNodeKind; flags: TNodeFlags; typeId: PackedItemId; info: PackedLineInfo): PatchPos =
   result = PatchPos tree.nodes.len
   tree.nodes.add PackedNode(kind: kind, flags: flags, operand: 0, info: info,
                             typeId: typeId)
diff --git a/compiler/ic/to_packed_ast.nim b/compiler/ic/to_packed_ast.nim
index aa3b447b8..cf1e940d3 100644
--- a/compiler/ic/to_packed_ast.nim
+++ b/compiler/ic/to_packed_ast.nim
@@ -174,16 +174,16 @@ proc addCompilerProc*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
   m.compilerProcs.add((nameId, s.itemId.item))
 
 proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule)
-proc toPackedSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
-proc toPackedType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemId
+proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
+proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemId
 
 proc flush(c: var PackedEncoder; m: var PackedModule) =
   ## serialize any pending types or symbols from the context
   while true:
     if c.pendingTypes.len > 0:
-      discard toPackedType(c.pendingTypes.pop, c, m)
+      discard storeType(c.pendingTypes.pop, c, m)
     elif c.pendingSyms.len > 0:
-      discard toPackedSym(c.pendingSyms.pop, c, m)
+      discard storeSym(c.pendingSyms.pop, c, m)
     else:
       break
 
@@ -210,16 +210,6 @@ proc safeItemId(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemI
     result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m),
                           item: s.itemId.item)
 
-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.nodes.add PackedNode(kind: nkModuleRef, operand: 3.int32, # spans 3 nodes in total
-                          typeId: toPackedType(n.typ, c, m), info: info)
-  ir.nodes.add PackedNode(kind: nkInt32Lit, info: info,
-                          operand: toLitId(n.sym.itemId.module.FileIndex, c, m).int32)
-  ir.nodes.add PackedNode(kind: nkInt32Lit, info: info,
-                          operand: n.sym.itemId.item)
-
 proc addMissing(c: var PackedEncoder; p: PSym) =
   ## consider queuing a symbol for later addition to the packed tree
   if p != nil and p.itemId.module == c.thisModule:
@@ -241,7 +231,36 @@ template storeNode(dest, src, field) =
     nodeId = emptyNodeId
   dest.field = nodeId
 
-proc toPackedType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemId =
+proc storeTypeLater(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemId =
+  # We store multiple different trees in m.bodies. For this to work out, we
+  # cannot immediately store types/syms. We enqueue them instead to ensure
+  # we only write one tree into m.bodies after the other.
+  if t.isNil: return nilItemId
+
+  if t.uniqueId.module != c.thisModule:
+    # XXX Assert here that it already was serialized in the foreign module!
+    # it is a foreign type:
+    assert t.uniqueId.module >= 0
+    assert t.uniqueId.item > 0
+    return PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item)
+  assert t.itemId.module >= 0
+  assert t.uniqueId.item > 0
+  result = PackedItemId(module: toLitId(t.itemId.module.FileIndex, c, m), item: t.uniqueId.item)
+  addMissing(c, t)
+
+proc storeSymLater(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId =
+  if s.isNil: return nilItemId
+  assert s.itemId.module >= 0
+  if s.itemId.module != c.thisModule:
+    # XXX Assert here that it already was serialized in the foreign module!
+    # it is a foreign symbol:
+    assert s.itemId.module >= 0
+    return PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item)
+  assert s.itemId.module >= 0
+  result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item)
+  addMissing(c, s)
+
+proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemId =
   ## serialize a ptype
   if t.isNil: return nilItemId
 
@@ -249,6 +268,7 @@ proc toPackedType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedIt
     # XXX Assert here that it already was serialized in the foreign module!
     # it is a foreign type:
     assert t.uniqueId.module >= 0
+    assert t.uniqueId.item > 0
     return PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item)
 
   if not c.typeMarker.containsOrIncl(t.uniqueId.item):
@@ -264,9 +284,9 @@ proc toPackedType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedIt
       c.addMissing s
       p.attachedOps[op] = s.safeItemId(c, m)
 
-    p.typeInst = t.typeInst.toPackedType(c, m)
+    p.typeInst = t.typeInst.storeType(c, m)
     for kid in items t.sons:
-      p.types.add kid.toPackedType(c, m)
+      p.types.add kid.storeType(c, m)
     for i, s in items t.methods:
       c.addMissing s
       p.methods.add (i, s.safeItemId(c, m))
@@ -279,6 +299,7 @@ proc toPackedType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedIt
     m.sh.types[t.uniqueId.item] = p
 
   assert t.itemId.module >= 0
+  assert t.uniqueId.item > 0
   result = PackedItemId(module: toLitId(t.itemId.module.FileIndex, c, m), item: t.uniqueId.item)
 
 proc toPackedLib(l: PLib; c: var PackedEncoder; m: var PackedModule): PackedLib =
@@ -290,7 +311,7 @@ proc toPackedLib(l: PLib; c: var PackedEncoder; m: var PackedModule): PackedLib
   result.name = toLitId($l.name, m)
   storeNode(result, l, path)
 
-proc toPackedSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId =
+proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId =
   ## serialize a psym
   if s.isNil: return nilItemId
 
@@ -321,7 +342,7 @@ proc toPackedSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedIte
 
     p.externalName = toLitId(if s.loc.r.isNil: "" else: $s.loc.r, m)
     c.addMissing s.typ
-    p.typ = s.typ.toPackedType(c, m)
+    p.typ = s.typ.storeType(c, m)
     c.addMissing s.owner
     p.owner = s.owner.safeItemId(c, m)
     p.annex = toPackedLib(s.annex, c, m)
@@ -334,70 +355,77 @@ proc toPackedSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedIte
   assert s.itemId.module >= 0
   result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item)
 
-proc toSymNode(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) =
-  ## store a local or remote psym reference in the tree
-  assert n.kind == nkSym
-  template s: PSym = n.sym
-  let id = s.toPackedSym(c, m).item
-  if s.itemId.module == c.thisModule:
-    # it is a symbol that belongs to the module we're currently
-    # packing:
-    ir.addSym(id, toPackedInfo(n.info, c, m))
-  else:
-    # store it as an external module reference:
-    addModuleRef(n, ir, c, m)
+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.nodes.add PackedNode(kind: nkModuleRef, operand: 3.int32, # spans 3 nodes in total
+                          typeId: storeTypeLater(n.typ, c, m), info: info)
+  ir.nodes.add PackedNode(kind: nkInt32Lit, info: info,
+                          operand: toLitId(n.sym.itemId.module.FileIndex, c, m).int32)
+  ir.nodes.add PackedNode(kind: nkInt32Lit, info: info,
+                          operand: n.sym.itemId.item)
 
 proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) =
   ## serialize a node into the tree
-  if n.isNil: return
+  if n == nil:
+    ir.nodes.add PackedNode(kind: nkNilRodNode, flags: {}, operand: 1)
+    return
   let info = toPackedInfo(n.info, c, m)
   case n.kind
   of nkNone, nkEmpty, nkNilLit, nkType:
     ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, operand: 0,
-                            typeId: toPackedType(n.typ, c, m), info: info)
+                            typeId: storeTypeLater(n.typ, c, m), info: info)
   of nkIdent:
     ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
                             operand: int32 getOrIncl(m.sh.strings, n.ident.s),
-                            typeId: toPackedType(n.typ, c, m), info: info)
+                            typeId: storeTypeLater(n.typ, c, m), info: info)
   of nkSym:
-    toSymNode(n, ir, c, m)
+    if n.sym.itemId.module == c.thisModule:
+      # it is a symbol that belongs to the module we're currently
+      # packing:
+      let id = n.sym.storeSymLater(c, m).item
+      ir.nodes.add PackedNode(kind: nkSym, flags: n.flags, operand: id,
+                              typeId: storeTypeLater(n.typ, c, m), info: info)
+    else:
+      # store it as an external module reference:
+      addModuleRef(n, ir, c, m)
   of directIntLit:
     ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
                             operand: int32(n.intVal),
-                            typeId: toPackedType(n.typ, c, m), info: info)
+                            typeId: storeTypeLater(n.typ, c, m), info: info)
   of externIntLit:
     ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
                             operand: int32 getOrIncl(m.sh.integers, n.intVal),
-                            typeId: toPackedType(n.typ, c, m), info: info)
+                            typeId: storeTypeLater(n.typ, c, m), info: info)
   of nkStrLit..nkTripleStrLit:
     ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
                             operand: int32 getOrIncl(m.sh.strings, n.strVal),
-                            typeId: toPackedType(n.typ, c, m), info: info)
+                            typeId: storeTypeLater(n.typ, c, m), info: info)
   of nkFloatLit..nkFloat128Lit:
     ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
                             operand: int32 getOrIncl(m.sh.floats, n.floatVal),
-                            typeId: toPackedType(n.typ, c, m), info: info)
+                            typeId: storeTypeLater(n.typ, c, m), info: info)
   else:
     let patchPos = ir.prepare(n.kind, n.flags,
-                              toPackedType(n.typ, c, m), info)
+                              storeTypeLater(n.typ, c, m), info)
     for i in 0..<n.len:
       toPackedNode(n[i], ir, c, m)
     ir.patch patchPos
 
-  when false:
-    ir.flush c   # flush any pending types and symbols
-
 proc addPragmaComputation*(c: var PackedEncoder; m: var PackedModule; n: PNode) =
   toPackedNode(n, m.toReplay, c, m)
 
-proc toPackedNodeIgnoreProcDefs*(n: PNode, encoder: var PackedEncoder; m: var PackedModule) =
+proc toPackedNodeIgnoreProcDefs(n: PNode, encoder: var PackedEncoder; m: var PackedModule) =
   case n.kind
   of routineDefs:
     # we serialize n[namePos].sym instead
     if n[namePos].kind == nkSym:
-      discard toPackedSym(n[namePos].sym, encoder, m)
+      discard storeSym(n[namePos].sym, encoder, m)
     else:
       toPackedNode(n, m.topLevel, encoder, m)
+  of nkStmtList, nkStmtListExpr:
+    for it in n:
+      toPackedNodeIgnoreProcDefs(it, encoder, m)
   else:
     toPackedNode(n, m.topLevel, encoder, m)
 
@@ -549,7 +577,7 @@ type
 type
   ModuleStatus* = enum
     undefined,
-    storing,
+    storing,  # state is strictly for stress-testing purposes
     loading,
     loaded,
     outdated
@@ -586,6 +614,10 @@ proc translateLineInfo(c: var PackedDecoder; g: var PackedModuleGraph; thisModul
 proc loadNodes(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
                tree: PackedTree; n: NodePos): PNode =
   let k = n.kind
+  if k == nkNilRodNode:
+    return nil
+  when false:
+    echo "loading node ", c.config $ translateLineInfo(c, g, thisModule, n.info)
   result = newNodeIT(k, translateLineInfo(c, g, thisModule, n.info),
     loadType(c, g, thisModule, n.typ))
   result.flags = n.flags
@@ -613,7 +645,7 @@ proc loadNodes(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
     result.sym = loadSym(c, g, thisModule, PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand))
   else:
     for n0 in sonsReadonly(tree, n):
-      result.add loadNodes(c, g, thisModule, tree, n0)
+      result.addAllowNil loadNodes(c, g, thisModule, tree, n0)
 
 proc loadProcHeader(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
                     tree: PackedTree; n: NodePos): PNode =
@@ -705,13 +737,11 @@ proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s:
       setLen g[si].syms, g[si].fromDisk.sh.syms.len
 
     if g[si].syms[s.item] == nil:
-      let packed = addr(g[si].fromDisk.sh.syms[s.item])
-
-      if packed.kind != skModule:
-        result = symHeaderFromPacked(c, g, packed[], si, s.item)
+      if g[si].fromDisk.sh.syms[s.item].kind != skModule:
+        result = symHeaderFromPacked(c, g, g[si].fromDisk.sh.syms[s.item], si, s.item)
         # store it here early on, so that recursions work properly:
         g[si].syms[s.item] = result
-        symBodyFromPacked(c, g, packed[], si, s.item, result)
+        symBodyFromPacked(c, g, g[si].fromDisk.sh.syms[s.item], si, s.item, result)
       else:
         result = g[si].module
         assert result != nil
@@ -724,7 +754,8 @@ proc typeHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
   result = PType(itemId: ItemId(module: si, item: t.nonUniqueId), kind: t.kind,
                 flags: t.flags, size: t.size, align: t.align,
                 paddingAtEnd: t.paddingAtEnd, lockLevel: t.lockLevel,
-                uniqueId: ItemId(module: si, item: item))
+                uniqueId: ItemId(module: si, item: item),
+                callConv: t.callConv)
 
 proc typeBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
                         t: PackedType; si, item: int32; result: PType) =
@@ -745,18 +776,20 @@ proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t
   else:
     let si = moduleIndex(c, g, thisModule, t)
     assert g[si].status in {loaded, storing}
+    assert t.item > 0
+
     if not g[si].typesInit:
       g[si].typesInit = true
       setLen g[si].types, g[si].fromDisk.sh.types.len
 
     if g[si].types[t.item] == nil:
-      let packed = addr(g[si].fromDisk.sh.types[t.item])
-      result = typeHeaderFromPacked(c, g, packed[], si, t.item)
+      result = typeHeaderFromPacked(c, g, g[si].fromDisk.sh.types[t.item], si, t.item)
       # store it here early on, so that recursions work properly:
       g[si].types[t.item] = result
-      typeBodyFromPacked(c, g, packed[], si, t.item, result)
+      typeBodyFromPacked(c, g, g[si].fromDisk.sh.types[t.item], si, t.item, result)
     else:
       result = g[si].types[t.item]
+    assert result.itemId.item > 0
 
 proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
                        fileIdx: FileIndex; m: var LoadedModule) =
@@ -794,6 +827,7 @@ proc loadToReplayNodes(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCa
 
 proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
                     fileIdx: FileIndex): bool =
+  # Does the file belong to the fileIdx need to be recompiled?
   let m = int(fileIdx)
   if m >= g.len:
     g.setLen(m+1)
@@ -822,6 +856,7 @@ proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache
       g[m].status = outdated
       result = true
   of loading, loaded:
+    # For loading: Assume no recompile is required.
     result = false
   of outdated, storing:
     result = true
@@ -857,6 +892,19 @@ proc loadProcBody*(config: ConfigRef, cache: IdentCache;
   assert pos != emptyNodeId
   result = loadProcBody(decoder, g, mId, g[mId].fromDisk.bodies, NodePos pos)
 
+proc checkForHoles(m: PackedModule; config: ConfigRef; moduleId: int) =
+  var bugs = 0
+  for i in 1 .. high(m.sh.syms):
+    if m.sh.syms[i].kind == skUnknown:
+      echo "EMPTY ID ", i, " module ", moduleId, " ", toFullPath(config, FileIndex(moduleId))
+      inc bugs
+  assert bugs == 0
+  when false:
+    var nones = 0
+    for i in 1 .. high(m.sh.types):
+      inc nones, m.sh.types[i].kind == tyNone
+    assert nones < 1
+
 proc simulateLoadedModule*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
                            moduleSym: PSym; m: PackedModule) =
   # For now only used for heavy debugging. In the future we could use this to reduce the
diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim
index e79be6776..74cc07df5 100644
--- a/compiler/magicsys.nim
+++ b/compiler/magicsys.nim
@@ -17,9 +17,6 @@ export createMagic
 
 proc nilOrSysInt*(g: ModuleGraph): PType = g.sysTypes[tyInt]
 
-proc registerSysType*(g: ModuleGraph; t: PType) =
-  if g.sysTypes[t.kind] == nil: g.sysTypes[t.kind] = t
-
 proc newSysType(g: ModuleGraph; kind: TTypeKind, size: int): PType =
   result = newType(kind, nextTypeId(g.idgen), g.systemModule)
   result.size = size
@@ -88,24 +85,6 @@ proc resetSysTypes*(g: ModuleGraph) =
   for i in low(g.sysTypes)..high(g.sysTypes):
     g.sysTypes[i] = nil
 
-  for i in low(g.intTypeCache)..high(g.intTypeCache):
-    g.intTypeCache[i] = nil
-
-proc getIntLitType*(g: ModuleGraph; literal: PNode): PType =
-  # we cache some common integer literal types for performance:
-  let value = literal.intVal
-  if value >= low(g.intTypeCache) and value <= high(g.intTypeCache):
-    result = g.intTypeCache[value.int]
-    if result == nil:
-      let ti = getSysType(g, literal.info, tyInt)
-      result = copyType(ti, nextTypeId(g.idgen), ti.owner)
-      result.n = literal
-      g.intTypeCache[value.int] = result
-  else:
-    let ti = getSysType(g, literal.info, tyInt)
-    result = copyType(ti, nextTypeId(g.idgen), ti.owner)
-    result.n = literal
-
 proc getFloatLitType*(g: ModuleGraph; literal: PNode): PType =
   # for now we do not cache these:
   result = newSysType(g, tyFloat, size=8)
@@ -125,35 +104,6 @@ proc addSonSkipIntLit*(father, son: PType; id: IdGenerator) =
   father.sons.add(s)
   propagateToOwner(father, s)
 
-proc setIntLitType*(g: ModuleGraph; result: PNode) =
-  let i = result.intVal
-  case g.config.target.intSize
-  of 8: result.typ = getIntLitType(g, result)
-  of 4:
-    if i >= low(int32) and i <= high(int32):
-      result.typ = getIntLitType(g, result)
-    else:
-      result.typ = getSysType(g, result.info, tyInt64)
-  of 2:
-    if i >= low(int16) and i <= high(int16):
-      result.typ = getIntLitType(g, result)
-    elif i >= low(int32) and i <= high(int32):
-      result.typ = getSysType(g, result.info, tyInt32)
-    else:
-      result.typ = getSysType(g, result.info, tyInt64)
-  of 1:
-    # 8 bit CPUs are insane ...
-    if i >= low(int8) and i <= high(int8):
-      result.typ = getIntLitType(g, result)
-    elif i >= low(int16) and i <= high(int16):
-      result.typ = getSysType(g, result.info, tyInt16)
-    elif i >= low(int32) and i <= high(int32):
-      result.typ = getSysType(g, result.info, tyInt32)
-    else:
-      result.typ = getSysType(g, result.info, tyInt64)
-  else:
-    internalError(g.config, result.info, "invalid int size")
-
 proc getCompilerProc*(g: ModuleGraph; name: string): PSym =
   let ident = getIdent(g.cache, name)
   result = strTableGet(g.compilerprocs, ident)
diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim
index 9b174d281..8498cb2b9 100644
--- a/compiler/modulegraphs.nim
+++ b/compiler/modulegraphs.nim
@@ -55,16 +55,14 @@ type
     compilerprocs*: TStrTable
     exposed*: TStrTable
     packageTypes*: TStrTable
-    intTypeCache*: array[-5..64, PType]
-    opContains*, opNot*: PSym
     emptyNode*: PNode
     canonTypes*: Table[SigHash, PType]
     symBodyHashes*: Table[int, SigHash] # symId to digest mapping
     importModuleCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PSym {.nimcall.}
     includeFileCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PNode {.nimcall.}
-    cacheSeqs*: Table[string, PNode] # state that is shared to support the 'macrocache' API
-    cacheCounters*: Table[string, BiggestInt]
-    cacheTables*: Table[string, BTree[string, PNode]]
+    cacheSeqs*: Table[string, PNode] # state that is shared to support the 'macrocache' API; IC: implemented
+    cacheCounters*: Table[string, BiggestInt] # IC: implemented
+    cacheTables*: Table[string, BTree[string, PNode]] # IC: implemented
     passes*: seq[TPass]
     onDefinition*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
     onDefinitionResolveForward*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
@@ -245,6 +243,8 @@ proc registerModule*(g: ModuleGraph; m: PSym) =
 
 proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
   result = ModuleGraph()
+  # A module ID of -1 means that the symbol is not attached to a module at all,
+  # but to the module graph:
   result.idgen = IdGenerator(module: -1'i32, symId: 0'i32, typeId: 0'i32)
   initStrTable(result.packageSyms)
   result.deps = initIntSet()
@@ -259,8 +259,6 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
   initStrTable(result.compilerprocs)
   initStrTable(result.exposed)
   initStrTable(result.packageTypes)
-  result.opNot = createMagic(result, "not", mNot)
-  result.opContains = createMagic(result, "contains", mInSet)
   result.emptyNode = newNode(nkEmpty)
   result.cacheSeqs = initTable[string, PNode]()
   result.cacheCounters = initTable[string, BiggestInt]()
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 6f3b15867..15b7eee4a 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -505,6 +505,8 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
 proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} =
   var c = newContext(graph, module)
   c.idgen = idgen
+  c.enforceVoidContext = newType(tyTyped, nextTypeId(idgen), nil)
+
   if c.p != nil: internalError(graph.config, module.info, "sem.myOpen")
   c.semConstExpr = semConstExpr
   c.semExpr = semExpr
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 583077fbf..d974f6048 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -93,6 +93,9 @@ type
     imports*: seq[ImportedModule] # scope for all imported symbols
     topLevelScope*: PScope     # scope for all top-level symbols
     p*: PProcCon               # procedure context
+    intTypeCache*: array[-5..32, PType] # cache some common integer types
+                                        # to avoid type allocations
+    nilTypeCache*: PType
     matchedConcept*: ptr TMatchedConcept # the current concept being matched
     friendModules*: seq[PSym]  # friend modules; may access private data;
                                # this is used so that generic instantiations
@@ -149,17 +152,56 @@ type
     isAmbiguous*: bool # little hack
     features*: set[Feature]
     inTypeContext*: int
-    typesWithOps*: seq[(PType, PType)] #\
-      # We need to instantiate the type bound ops lazily after
-      # the generic type has been constructed completely. See
-      # tests/destructor/topttree.nim for an example that
-      # would otherwise fail.
     unusedImports*: seq[(PSym, TLineInfo)]
     exportIndirections*: HashSet[(int, int)]
     lastTLineInfo*: TLineInfo
 
 template config*(c: PContext): ConfigRef = c.graph.config
 
+proc getIntLitType*(c: PContext; literal: PNode): PType =
+  # we cache some common integer literal types for performance:
+  let value = literal.intVal
+  if value >= low(c.intTypeCache) and value <= high(c.intTypeCache):
+    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.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.n = literal
+
+proc setIntLitType*(c: PContext; result: PNode) =
+  let i = result.intVal
+  case c.config.target.intSize
+  of 8: result.typ = getIntLitType(c, result)
+  of 4:
+    if i >= low(int32) and i <= high(int32):
+      result.typ = getIntLitType(c, result)
+    else:
+      result.typ = getSysType(c.graph, result.info, tyInt64)
+  of 2:
+    if i >= low(int16) and i <= high(int16):
+      result.typ = getIntLitType(c, result)
+    elif i >= low(int32) and i <= high(int32):
+      result.typ = getSysType(c.graph, result.info, tyInt32)
+    else:
+      result.typ = getSysType(c.graph, result.info, tyInt64)
+  of 1:
+    # 8 bit CPUs are insane ...
+    if i >= low(int8) and i <= high(int8):
+      result.typ = getIntLitType(c, result)
+    elif i >= low(int16) and i <= high(int16):
+      result.typ = getSysType(c.graph, result.info, tyInt16)
+    elif i >= low(int32) and i <= high(int32):
+      result.typ = getSysType(c.graph, result.info, tyInt32)
+    else:
+      result.typ = getSysType(c.graph, result.info, tyInt64)
+  else:
+    internalError(c.config, result.info, "invalid int size")
+
 proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
   result.genericSym = s
   result.inst = inst
@@ -250,7 +292,6 @@ proc popOptionEntry*(c: PContext) =
 
 proc newContext*(graph: ModuleGraph; module: PSym): PContext =
   new(result)
-  result.enforceVoidContext = PType(kind: tyTyped)
   result.optionStack = @[newOptionEntry(graph.config)]
   result.libs = @[]
   result.module = module
@@ -265,7 +306,6 @@ proc newContext*(graph: ModuleGraph; module: PSym): PContext =
   result.cache = graph.cache
   result.graph = graph
   initStrTable(result.signatures)
-  result.typesWithOps = @[]
   result.features = graph.config.features
   if graph.config.symbolFiles != disabledSf:
     let id = module.position
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 4a04cfb6d..343ff0eda 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1072,7 +1072,7 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
           s = newNodeIT(nkCurly, n.info, setType)
           for j in 0..<it.len - 1: s.add copyTree(it[j])
           var inExpr = newNodeIT(nkCall, n.info, getSysType(c.graph, n.info, tyBool))
-          inExpr.add newSymNode(c.graph.opContains, n.info)
+          inExpr.add newSymNode(getSysMagic(c.graph, n.info, "contains", mInSet), n.info)
           inExpr.add s
           inExpr.add copyTree(r[0])
           check.add inExpr
@@ -1085,11 +1085,11 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
             check = newNodeI(nkCheckedFieldExpr, n.info)
             check.add c.graph.emptyNode # make space for access node
           var inExpr = newNodeIT(nkCall, n.info, getSysType(c.graph, n.info, tyBool))
-          inExpr.add newSymNode(c.graph.opContains, n.info)
+          inExpr.add newSymNode(getSysMagic(c.graph, n.info, "contains", mInSet), n.info)
           inExpr.add s
           inExpr.add copyTree(r[0])
           var notExpr = newNodeIT(nkCall, n.info, getSysType(c.graph, n.info, tyBool))
-          notExpr.add newSymNode(c.graph.opNot, n.info)
+          notExpr.add newSymNode(getSysMagic(c.graph, n.info, "not", mNot), n.info)
           notExpr.add inExpr
           check.add notExpr
           return
@@ -2641,6 +2641,14 @@ proc hoistParamsUsedInDefault(c: PContext, call, letSection, defExpr: var PNode)
     for i in 0..<defExpr.safeLen:
       hoistParamsUsedInDefault(c, call, letSection, defExpr[i])
 
+proc getNilType(c: PContext): PType =
+  result = c.nilTypeCache
+  if result == nil:
+    result = newTypeS(tyNil, c)
+    result.size = c.config.target.ptrSize
+    result.align = c.config.target.ptrSize.int16
+    c.nilTypeCache = result
+
 proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   when defined(nimCompilerStackraceHints):
     setFrameMsg c.config$n.info & " " & $n.kind
@@ -2676,9 +2684,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkEmpty, nkNone, nkCommentStmt, nkType:
     discard
   of nkNilLit:
-    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyNil)
+    if result.typ == nil: result.typ = getNilType(c)
   of nkIntLit:
-    if result.typ == nil: setIntLitType(c.graph, result)
+    if result.typ == nil: setIntLitType(c, result)
   of nkInt8Lit:
     if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt8)
   of nkInt16Lit:
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 4cc2dcba0..a3b9a8dde 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -22,13 +22,19 @@ proc errorType*(g: ModuleGraph): PType =
   result = newType(tyError, nextTypeId(g.idgen), g.owners[^1])
   result.flags.incl tfCheckedForDestructor
 
-proc newIntNodeT*(intVal: Int128, n: PNode; g: ModuleGraph): PNode =
+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.n = literal
+
+proc newIntNodeT*(intVal: Int128, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
   result = newIntTypeNode(intVal, n.typ)
   # See bug #6989. 'pred' et al only produce an int literal type if the
   # original type was 'int', not a distinct int etc.
   if n.typ.kind == tyInt:
     # access cache for the int lit type
-    result.typ = getIntLitType(g, result)
+    result.typ = getIntLitTypeG(g, result, idgen)
   result.info = n.info
 
 proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode; g: ModuleGraph): PNode =
@@ -47,33 +53,33 @@ proc newStrNodeT*(strVal: string, n: PNode; g: ModuleGraph): PNode =
 proc getConstExpr*(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
   # evaluates the constant expression or returns nil if it is no constant
   # expression
-proc evalOp*(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode
+proc evalOp*(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
 
 proc checkInRange(conf: ConfigRef; n: PNode, res: Int128): bool =
   res in firstOrd(conf, n.typ)..lastOrd(conf, n.typ)
 
-proc foldAdd(a, b: Int128, n: PNode; g: ModuleGraph): PNode =
+proc foldAdd(a, b: Int128, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
   let res = a + b
   if checkInRange(g.config, n, res):
-    result = newIntNodeT(res, n, g)
+    result = newIntNodeT(res, n, idgen, g)
 
-proc foldSub(a, b: Int128, n: PNode; g: ModuleGraph): PNode =
+proc foldSub(a, b: Int128, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
   let res = a - b
   if checkInRange(g.config, n, res):
-    result = newIntNodeT(res, n, g)
+    result = newIntNodeT(res, n, idgen, g)
 
-proc foldUnarySub(a: Int128, n: PNode, g: ModuleGraph): PNode =
+proc foldUnarySub(a: Int128, n: PNode; idgen: IdGenerator, g: ModuleGraph): PNode =
   if a != firstOrd(g.config, n.typ):
-    result = newIntNodeT(-a, n, g)
+    result = newIntNodeT(-a, n, idgen, g)
 
-proc foldAbs(a: Int128, n: PNode; g: ModuleGraph): PNode =
+proc foldAbs(a: Int128, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
   if a != firstOrd(g.config, n.typ):
-    result = newIntNodeT(abs(a), n, g)
+    result = newIntNodeT(abs(a), n, idgen, g)
 
-proc foldMul(a, b: Int128, n: PNode; g: ModuleGraph): PNode =
+proc foldMul(a, b: Int128, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
   let res = a * b
   if checkInRange(g.config, n, res):
-    return newIntNodeT(res, n, g)
+    return newIntNodeT(res, n, idgen, g)
 
 proc ordinalValToString*(a: PNode; g: ModuleGraph): string =
   # because $ has the param ordinal[T], `a` is not necessarily an enum, but an
@@ -115,68 +121,68 @@ proc pickIntRange(a, b: PType): PType =
 proc isIntRangeOrLit(t: PType): bool =
   result = isIntRange(t) or isIntLit(t)
 
-proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
+proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
   # b and c may be nil
   result = nil
   case m
-  of mOrd: result = newIntNodeT(getOrdValue(a), n, g)
-  of mChr: result = newIntNodeT(getInt(a), n, g)
-  of mUnaryMinusI, mUnaryMinusI64: result = foldUnarySub(getInt(a), n, g)
+  of mOrd: result = newIntNodeT(getOrdValue(a), n, idgen, g)
+  of mChr: result = newIntNodeT(getInt(a), n, idgen, g)
+  of mUnaryMinusI, mUnaryMinusI64: result = foldUnarySub(getInt(a), n, idgen, g)
   of mUnaryMinusF64: result = newFloatNodeT(-getFloat(a), n, g)
-  of mNot: result = newIntNodeT(One - getInt(a), n, g)
-  of mCard: result = newIntNodeT(toInt128(nimsets.cardSet(g.config, a)), n, g)
+  of mNot: result = newIntNodeT(One - getInt(a), n, idgen, g)
+  of mCard: result = newIntNodeT(toInt128(nimsets.cardSet(g.config, a)), n, idgen, g)
   of mBitnotI:
     if n.typ.isUnsigned:
-      result = newIntNodeT(bitnot(getInt(a)).maskBytes(int(n.typ.size)), n, g)
+      result = newIntNodeT(bitnot(getInt(a)).maskBytes(int(n.typ.size)), n, idgen, g)
     else:
-      result = newIntNodeT(bitnot(getInt(a)), n, g)
-  of mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, g)
+      result = newIntNodeT(bitnot(getInt(a)), n, idgen, g)
+  of mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, idgen, g)
   of mLengthSeq, mLengthOpenArray, mLengthStr:
     if a.kind == nkNilLit:
-      result = newIntNodeT(Zero, n, g)
+      result = newIntNodeT(Zero, n, idgen, g)
     elif a.kind in {nkStrLit..nkTripleStrLit}:
       if a.typ.kind == tyString:
-        result = newIntNodeT(toInt128(a.strVal.len), n, g)
+        result = newIntNodeT(toInt128(a.strVal.len), n, idgen, g)
       elif a.typ.kind == tyCString:
-        result = newIntNodeT(toInt128(nimCStrLen(a.strVal)), n, g)
+        result = newIntNodeT(toInt128(nimCStrLen(a.strVal)), n, idgen, g)
     else:
-      result = newIntNodeT(toInt128(a.len), n, g)
+      result = newIntNodeT(toInt128(a.len), n, idgen, g)
   of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
   # XXX: Hides overflow/underflow
-  of mAbsI: result = foldAbs(getInt(a), n, g)
-  of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n, g)
-  of mPred: result = foldSub(getOrdValue(a), getInt(b), n, g)
-  of mAddI: result = foldAdd(getInt(a), getInt(b), n, g)
-  of mSubI: result = foldSub(getInt(a), getInt(b), n, g)
-  of mMulI: result = foldMul(getInt(a), getInt(b), n, g)
+  of mAbsI: result = foldAbs(getInt(a), n, idgen, g)
+  of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n, idgen, g)
+  of mPred: result = foldSub(getOrdValue(a), getInt(b), n, idgen, g)
+  of mAddI: result = foldAdd(getInt(a), getInt(b), n, idgen, g)
+  of mSubI: result = foldSub(getInt(a), getInt(b), n, idgen, g)
+  of mMulI: result = foldMul(getInt(a), getInt(b), n, idgen, g)
   of mMinI:
     let argA = getInt(a)
     let argB = getInt(b)
-    result = newIntNodeT(if argA < argB: argA else: argB, n, g)
+    result = newIntNodeT(if argA < argB: argA else: argB, n, idgen, g)
   of mMaxI:
     let argA = getInt(a)
     let argB = getInt(b)
-    result = newIntNodeT(if argA > argB: argA else: argB, n, g)
+    result = newIntNodeT(if argA > argB: argA else: argB, n, idgen, g)
   of mShlI:
     case skipTypes(n.typ, abstractRange).kind
-    of tyInt8: result = newIntNodeT(toInt128(toInt8(getInt(a)) shl toInt64(getInt(b))), n, g)
-    of tyInt16: result = newIntNodeT(toInt128(toInt16(getInt(a)) shl toInt64(getInt(b))), n, g)
-    of tyInt32: result = newIntNodeT(toInt128(toInt32(getInt(a)) shl toInt64(getInt(b))), n, g)
-    of tyInt64: result = newIntNodeT(toInt128(toInt64(getInt(a)) shl toInt64(getInt(b))), n, g)
+    of tyInt8: result = newIntNodeT(toInt128(toInt8(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
+    of tyInt16: result = newIntNodeT(toInt128(toInt16(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
+    of tyInt32: result = newIntNodeT(toInt128(toInt32(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
+    of tyInt64: result = newIntNodeT(toInt128(toInt64(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
     of tyInt:
       if g.config.target.intSize == 4:
-        result = newIntNodeT(toInt128(toInt32(getInt(a)) shl toInt64(getInt(b))), n, g)
+        result = newIntNodeT(toInt128(toInt32(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
       else:
-        result = newIntNodeT(toInt128(toInt64(getInt(a)) shl toInt64(getInt(b))), n, g)
-    of tyUInt8: result = newIntNodeT(toInt128(toUInt8(getInt(a)) shl toInt64(getInt(b))), n, g)
-    of tyUInt16: result = newIntNodeT(toInt128(toUInt16(getInt(a)) shl toInt64(getInt(b))), n, g)
-    of tyUInt32: result = newIntNodeT(toInt128(toUInt32(getInt(a)) shl toInt64(getInt(b))), n, g)
-    of tyUInt64: result = newIntNodeT(toInt128(toUInt64(getInt(a)) shl toInt64(getInt(b))), n, g)
+        result = newIntNodeT(toInt128(toInt64(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
+    of tyUInt8: result = newIntNodeT(toInt128(toUInt8(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
+    of tyUInt16: result = newIntNodeT(toInt128(toUInt16(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
+    of tyUInt32: result = newIntNodeT(toInt128(toUInt32(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
+    of tyUInt64: result = newIntNodeT(toInt128(toUInt64(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
     of tyUInt:
       if g.config.target.intSize == 4:
-        result = newIntNodeT(toInt128(toUInt32(getInt(a)) shl toInt64(getInt(b))), n, g)
+        result = newIntNodeT(toInt128(toUInt32(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
       else:
-        result = newIntNodeT(toInt128(toUInt64(getInt(a)) shl toInt64(getInt(b))), n, g)
+        result = newIntNodeT(toInt128(toUInt64(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
     else: internalError(g.config, n.info, "constant folding for shl")
   of mShrI:
     var a = cast[uint64](getInt(a))
@@ -197,75 +203,75 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
         # unsigned and 64 bit integers don't need masking
         discard
     let c = cast[BiggestInt](a shr b)
-    result = newIntNodeT(toInt128(c), n, g)
+    result = newIntNodeT(toInt128(c), n, idgen, g)
   of mAshrI:
     case skipTypes(n.typ, abstractRange).kind
-    of tyInt8: result =  newIntNodeT(toInt128(ashr(toInt8(getInt(a)), toInt8(getInt(b)))), n, g)
-    of tyInt16: result = newIntNodeT(toInt128(ashr(toInt16(getInt(a)), toInt16(getInt(b)))), n, g)
-    of tyInt32: result = newIntNodeT(toInt128(ashr(toInt32(getInt(a)), toInt32(getInt(b)))), n, g)
+    of tyInt8: result =  newIntNodeT(toInt128(ashr(toInt8(getInt(a)), toInt8(getInt(b)))), n, idgen, g)
+    of tyInt16: result = newIntNodeT(toInt128(ashr(toInt16(getInt(a)), toInt16(getInt(b)))), n, idgen, g)
+    of tyInt32: result = newIntNodeT(toInt128(ashr(toInt32(getInt(a)), toInt32(getInt(b)))), n, idgen, g)
     of tyInt64, tyInt:
-      result = newIntNodeT(toInt128(ashr(toInt64(getInt(a)), toInt64(getInt(b)))), n, g)
+      result = newIntNodeT(toInt128(ashr(toInt64(getInt(a)), toInt64(getInt(b)))), n, idgen, g)
     else: internalError(g.config, n.info, "constant folding for ashr")
   of mDivI:
     let argA = getInt(a)
     let argB = getInt(b)
     if argB != Zero and (argA != firstOrd(g.config, n.typ) or argB != NegOne):
-      result = newIntNodeT(argA div argB, n, g)
+      result = newIntNodeT(argA div argB, n, idgen, g)
   of mModI:
     let argA = getInt(a)
     let argB = getInt(b)
     if argB != Zero and (argA != firstOrd(g.config, n.typ) or argB != NegOne):
-      result = newIntNodeT(argA mod argB, n, g)
+      result = newIntNodeT(argA mod argB, n, idgen, g)
   of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n, g)
   of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n, g)
   of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n, g)
   of mDivF64:
     result = newFloatNodeT(getFloat(a) / getFloat(b), n, g)
-  of mIsNil: result = newIntNodeT(toInt128(ord(a.kind == nkNilLit)), n, g)
+  of mIsNil: result = newIntNodeT(toInt128(ord(a.kind == nkNilLit)), n, idgen, g)
   of mLtI, mLtB, mLtEnum, mLtCh:
-    result = newIntNodeT(toInt128(ord(getOrdValue(a) < getOrdValue(b))), n, g)
+    result = newIntNodeT(toInt128(ord(getOrdValue(a) < getOrdValue(b))), n, idgen, g)
   of mLeI, mLeB, mLeEnum, mLeCh:
-    result = newIntNodeT(toInt128(ord(getOrdValue(a) <= getOrdValue(b))), n, g)
+    result = newIntNodeT(toInt128(ord(getOrdValue(a) <= getOrdValue(b))), n, idgen, g)
   of mEqI, mEqB, mEqEnum, mEqCh:
-    result = newIntNodeT(toInt128(ord(getOrdValue(a) == getOrdValue(b))), n, g)
-  of mLtF64: result = newIntNodeT(toInt128(ord(getFloat(a) < getFloat(b))), n, g)
-  of mLeF64: result = newIntNodeT(toInt128(ord(getFloat(a) <= getFloat(b))), n, g)
-  of mEqF64: result = newIntNodeT(toInt128(ord(getFloat(a) == getFloat(b))), n, g)
-  of mLtStr: result = newIntNodeT(toInt128(ord(getStr(a) < getStr(b))), n, g)
-  of mLeStr: result = newIntNodeT(toInt128(ord(getStr(a) <= getStr(b))), n, g)
-  of mEqStr: result = newIntNodeT(toInt128(ord(getStr(a) == getStr(b))), n, g)
+    result = newIntNodeT(toInt128(ord(getOrdValue(a) == getOrdValue(b))), n, idgen, g)
+  of mLtF64: result = newIntNodeT(toInt128(ord(getFloat(a) < getFloat(b))), n, idgen, g)
+  of mLeF64: result = newIntNodeT(toInt128(ord(getFloat(a) <= getFloat(b))), n, idgen, g)
+  of mEqF64: result = newIntNodeT(toInt128(ord(getFloat(a) == getFloat(b))), n, idgen, g)
+  of mLtStr: result = newIntNodeT(toInt128(ord(getStr(a) < getStr(b))), n, idgen, g)
+  of mLeStr: result = newIntNodeT(toInt128(ord(getStr(a) <= getStr(b))), n, idgen, g)
+  of mEqStr: result = newIntNodeT(toInt128(ord(getStr(a) == getStr(b))), n, idgen, g)
   of mLtU:
-    result = newIntNodeT(toInt128(ord(`<%`(toInt64(getOrdValue(a)), toInt64(getOrdValue(b))))), n, g)
+    result = newIntNodeT(toInt128(ord(`<%`(toInt64(getOrdValue(a)), toInt64(getOrdValue(b))))), n, idgen, g)
   of mLeU:
-    result = newIntNodeT(toInt128(ord(`<=%`(toInt64(getOrdValue(a)), toInt64(getOrdValue(b))))), n, g)
-  of mBitandI, mAnd: result = newIntNodeT(bitand(a.getInt, b.getInt), n, g)
-  of mBitorI, mOr: result = newIntNodeT(bitor(getInt(a), getInt(b)), n, g)
-  of mBitxorI, mXor: result = newIntNodeT(bitxor(getInt(a), getInt(b)), n, g)
+    result = newIntNodeT(toInt128(ord(`<=%`(toInt64(getOrdValue(a)), toInt64(getOrdValue(b))))), n, idgen, g)
+  of mBitandI, mAnd: result = newIntNodeT(bitand(a.getInt, b.getInt), n, idgen, g)
+  of mBitorI, mOr: result = newIntNodeT(bitor(getInt(a), getInt(b)), n, idgen, g)
+  of mBitxorI, mXor: result = newIntNodeT(bitxor(getInt(a), getInt(b)), n, idgen, g)
   of mAddU:
     let val = maskBytes(getInt(a) + getInt(b), int(n.typ.size))
-    result = newIntNodeT(val, n, g)
+    result = newIntNodeT(val, n, idgen, g)
   of mSubU:
     let val = maskBytes(getInt(a) - getInt(b), int(n.typ.size))
-    result = newIntNodeT(val, n, g)
+    result = newIntNodeT(val, n, idgen, g)
     # echo "subU: ", val, " n: ", n, " result: ", val
   of mMulU:
     let val = maskBytes(getInt(a) * getInt(b), int(n.typ.size))
-    result = newIntNodeT(val, n, g)
+    result = newIntNodeT(val, n, idgen, g)
   of mModU:
     let argA = maskBytes(getInt(a), int(a.typ.size))
     let argB = maskBytes(getInt(b), int(a.typ.size))
     if argB != Zero:
-      result = newIntNodeT(argA mod argB, n, g)
+      result = newIntNodeT(argA mod argB, n, idgen, g)
   of mDivU:
     let argA = maskBytes(getInt(a), int(a.typ.size))
     let argB = maskBytes(getInt(b), int(a.typ.size))
     if argB != Zero:
-      result = newIntNodeT(argA div argB, n, g)
-  of mLeSet: result = newIntNodeT(toInt128(ord(containsSets(g.config, a, b))), n, g)
-  of mEqSet: result = newIntNodeT(toInt128(ord(equalSets(g.config, a, b))), n, g)
+      result = newIntNodeT(argA div argB, n, idgen, g)
+  of mLeSet: result = newIntNodeT(toInt128(ord(containsSets(g.config, a, b))), n, idgen, g)
+  of mEqSet: result = newIntNodeT(toInt128(ord(equalSets(g.config, a, b))), n, idgen, g)
   of mLtSet:
     result = newIntNodeT(toInt128(ord(
-      containsSets(g.config, a, b) and not equalSets(g.config, a, b))), n, g)
+      containsSets(g.config, a, b) and not equalSets(g.config, a, b))), n, idgen, g)
   of mMulSet:
     result = nimsets.intersectSets(g.config, a, b)
     result.info = n.info
@@ -276,7 +282,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
     result = nimsets.diffSets(g.config, a, b)
     result.info = n.info
   of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n, g)
-  of mInSet: result = newIntNodeT(toInt128(ord(inSet(a, b))), n, g)
+  of mInSet: result = newIntNodeT(toInt128(ord(inSet(a, b))), n, idgen, g)
   of mRepr:
     # BUGFIX: we cannot eval mRepr here for reasons that I forgot.
     discard
@@ -299,13 +305,13 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
     result = copyTree(a)
     result.typ = n.typ
   of mCompileOption:
-    result = newIntNodeT(toInt128(ord(commands.testCompileOption(g.config, a.getStr, n.info))), n, g)
+    result = newIntNodeT(toInt128(ord(commands.testCompileOption(g.config, a.getStr, n.info))), n, idgen, g)
   of mCompileOptionArg:
     result = newIntNodeT(toInt128(ord(
-      testCompileOptionArg(g.config, getStr(a), getStr(b), n.info))), n, g)
+      testCompileOptionArg(g.config, getStr(a), getStr(b), n.info))), n, idgen, g)
   of mEqProc:
     result = newIntNodeT(toInt128(ord(
-        exprStructuralEquivalent(a, b, strictSymEquality=true))), n, g)
+        exprStructuralEquivalent(a, b, strictSymEquality=true))), n, idgen, g)
   else: discard
 
 proc getConstIfExpr(c: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
@@ -351,7 +357,7 @@ proc magicCall(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
     if n.len > 3:
       c = getConstExpr(m, n[3], idgen, g)
       if c == nil: return
-  result = evalOp(s.magic, n, a, b, c, g)
+  result = evalOp(s.magic, n, a, b, c, idgen, g)
 
 proc getAppType(n: PNode; g: ModuleGraph): PNode =
   if g.config.globalOptions.contains(optGenDynLib):
@@ -368,7 +374,7 @@ proc rangeCheck(n: PNode, value: Int128; g: ModuleGraph) =
     localError(g.config, n.info, "cannot convert " & $value &
                                     " to " & typeToString(n.typ))
 
-proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode =
+proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): PNode =
   let dstTyp = skipTypes(n.typ, abstractRange - {tyTypeDesc})
   let srcTyp = skipTypes(a.typ, abstractRange - {tyTypeDesc})
 
@@ -382,9 +388,9 @@ proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode =
   of tyBool:
     case srcTyp.kind
     of tyFloat..tyFloat64:
-      result = newIntNodeT(toInt128(getFloat(a) != 0.0), n, g)
+      result = newIntNodeT(toInt128(getFloat(a) != 0.0), n, idgen, g)
     of tyChar, tyUInt..tyUInt64, tyInt..tyInt64:
-      result = newIntNodeT(toInt128(a.getOrdValue != 0), n, g)
+      result = newIntNodeT(toInt128(a.getOrdValue != 0), n, idgen, g)
     of tyBool, tyEnum: # xxx shouldn't we disallow `tyEnum`?
       result = a
       result.typ = n.typ
@@ -392,11 +398,11 @@ proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode =
   of tyInt..tyInt64, tyUInt..tyUInt64:
     case srcTyp.kind
     of tyFloat..tyFloat64:
-      result = newIntNodeT(toInt128(getFloat(a)), n, g)
+      result = newIntNodeT(toInt128(getFloat(a)), n, idgen, g)
     of tyChar, tyUInt..tyUInt64, tyInt..tyInt64:
       var val = a.getOrdValue
       if check: rangeCheck(n, val, g)
-      result = newIntNodeT(val, n, g)
+      result = newIntNodeT(val, n, idgen, g)
       if dstTyp.kind in {tyUInt..tyUInt64}:
         result.transitionIntKind(nkUIntLit)
     else:
@@ -493,13 +499,13 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
     var s = n.sym
     case s.kind
     of skEnumField:
-      result = newIntNodeT(toInt128(s.position), n, g)
+      result = newIntNodeT(toInt128(s.position), n, idgen, g)
     of skConst:
       case s.magic
-      of mIsMainModule: result = newIntNodeT(toInt128(ord(sfMainModule in m.flags)), n, g)
+      of mIsMainModule: result = newIntNodeT(toInt128(ord(sfMainModule in m.flags)), n, idgen, g)
       of mCompileDate: result = newStrNodeT(getDateStr(), n, g)
       of mCompileTime: result = newStrNodeT(getClockStr(), n, g)
-      of mCpuEndian: result = newIntNodeT(toInt128(ord(CPU[g.config.target.targetCPU].endian)), n, g)
+      of mCpuEndian: result = newIntNodeT(toInt128(ord(CPU[g.config.target.targetCPU].endian)), n, idgen, g)
       of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[g.config.target.targetOS].name), n, g)
       of mHostCPU: result = newStrNodeT(platform.CPU[g.config.target.targetCPU].name.toLowerAscii, n, g)
       of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[g.config.target.hostOS].name), n, g)
@@ -508,7 +514,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
       of mIntDefine:
         if isDefined(g.config, s.name.s):
           try:
-            result = newIntNodeT(toInt128(g.config.symbols[s.name.s].parseInt), n, g)
+            result = newIntNodeT(toInt128(g.config.symbols[s.name.s].parseInt), n, idgen, g)
           except ValueError:
             localError(g.config, s.info,
               "{.intdefine.} const was set to an invalid integer: '" &
@@ -523,7 +529,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
       of mBoolDefine:
         if isDefined(g.config, s.name.s):
           try:
-            result = newIntNodeT(toInt128(g.config.symbols[s.name.s].parseBool.int), n, g)
+            result = newIntNodeT(toInt128(g.config.symbols[s.name.s].parseBool.int), n, idgen, g)
           except ValueError:
             localError(g.config, s.info,
               "{.booldefine.} const was set to an invalid bool: '" &
@@ -569,30 +575,30 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
         if skipTypes(n[1].typ, abstractVarRange).kind in tyFloat..tyFloat64:
           result = newFloatNodeT(firstFloat(n[1].typ), n, g)
         else:
-          result = newIntNodeT(firstOrd(g.config, n[1].typ), n, g)
+          result = newIntNodeT(firstOrd(g.config, n[1].typ), n, idgen, g)
       of mHigh:
         if skipTypes(n[1].typ, abstractVar+{tyUserTypeClassInst}).kind notin
             {tySequence, tyString, tyCString, tyOpenArray, tyVarargs}:
           if skipTypes(n[1].typ, abstractVarRange).kind in tyFloat..tyFloat64:
             result = newFloatNodeT(lastFloat(n[1].typ), n, g)
           else:
-            result = newIntNodeT(lastOrd(g.config, skipTypes(n[1].typ, abstractVar)), n, g)
+            result = newIntNodeT(lastOrd(g.config, skipTypes(n[1].typ, abstractVar)), n, idgen, g)
         else:
           var a = getArrayConstr(m, n[1], idgen, g)
           if a.kind == nkBracket:
             # we can optimize it away:
-            result = newIntNodeT(toInt128(a.len-1), n, g)
+            result = newIntNodeT(toInt128(a.len-1), n, idgen, g)
       of mLengthOpenArray:
         var a = getArrayConstr(m, n[1], idgen, g)
         if a.kind == nkBracket:
           # we can optimize it away! This fixes the bug ``len(134)``.
-          result = newIntNodeT(toInt128(a.len), n, g)
+          result = newIntNodeT(toInt128(a.len), n, idgen, g)
         else:
           result = magicCall(m, n, idgen, g)
       of mLengthArray:
         # It doesn't matter if the argument is const or not for mLengthArray.
         # This fixes bug #544.
-        result = newIntNodeT(lengthOrd(g.config, n[1].typ), n, g)
+        result = newIntNodeT(lengthOrd(g.config, n[1].typ), n, idgen, g)
       of mSizeOf:
         result = foldSizeOf(g.config, n, nil)
       of mAlignOf:
@@ -675,7 +681,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
   of nkHiddenStdConv, nkHiddenSubConv, nkConv:
     var a = getConstExpr(m, n[1], idgen, g)
     if a == nil: return
-    result = foldConv(n, a, g, check=true)
+    result = foldConv(n, a, idgen, g, check=true)
   of nkDerefExpr, nkHiddenDeref:
     let a = getConstExpr(m, n[0], idgen, g)
     if a != nil and a.kind == nkNilLit:
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 69e414fa8..d5ce04389 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -71,7 +71,7 @@ proc semAsgnOpr(c: PContext; n: PNode): PNode =
 
 proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode =
   var r = isPartOf(n[1], n[2])
-  result = newIntNodeT(toInt128(ord(r)), n, c.graph)
+  result = newIntNodeT(toInt128(ord(r)), n, c.idgen, c.graph)
 
 proc expectIntLit(c: PContext, n: PNode): int =
   let x = c.semConstExpr(c, n)
@@ -179,15 +179,15 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
     let t = operand.skipTypes({tyVar, tyLent, tyGenericInst, tyAlias, tySink, tyInferred})
     let complexObj = containsGarbageCollectedRef(t) or
                      hasDestructor(t)
-    result = newIntNodeT(toInt128(ord(not complexObj)), traitCall, c.graph)
+    result = newIntNodeT(toInt128(ord(not complexObj)), traitCall, c.idgen, c.graph)
   of "isNamedTuple":
     var operand = operand.skipTypes({tyGenericInst})
     let cond = operand.kind == tyTuple and operand.n != nil
-    result = newIntNodeT(toInt128(ord(cond)), traitCall, c.graph)
+    result = newIntNodeT(toInt128(ord(cond)), traitCall, c.idgen, c.graph)
   of "tupleLen":
     var operand = operand.skipTypes({tyGenericInst})
     assert operand.kind == tyTuple, $operand.kind
-    result = newIntNodeT(toInt128(operand.len), traitCall, c.graph)
+    result = newIntNodeT(toInt128(operand.len), traitCall, c.idgen, c.graph)
   of "distinctBase":
     var arg = operand.skipTypes({tyGenericInst})
     if arg.kind == tyDistinct:
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index a76116b1c..15fe578f5 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -537,8 +537,6 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
       typFlags.incl taConcept
     typeAllowedCheck(c, a.info, typ, symkind, typFlags)
 
-    when false: liftTypeBoundOps(c, typ, a.info)
-    instAllTypeBoundOp(c, a.info)
     var tup = skipTypes(typ, {tyGenericInst, tyAlias, tySink})
     if a.kind == nkVarTuple:
       if tup.kind != tyTuple:
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 45f20da9b..057fb7d4a 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -1967,10 +1967,6 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
     result = newOrPrevType(tyError, prev, c)
   n.typ = result
   dec c.inTypeContext
-  if false: # c.inTypeContext == 0:
-    #if $n == "var seq[StackTraceEntry]":
-    #  echo "begin ", n
-    instAllTypeBoundOp(c, n.info)
 
 proc setMagicType(conf: ConfigRef; m: PSym, kind: TTypeKind, size: int) =
   # source : https://en.wikipedia.org/wiki/Data_structure_alignment#x86
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index e46ba937c..00c7cc558 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -432,7 +432,6 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
     # adding myseq for myseq[system.int]
     # sigmatch: Formal myseq[=destroy.T] real myseq[system.int]
     #echo "DESTROY: adding ", typeToString(newbody), " for ", typeToString(result, preferDesc)
-    #cl.c.typesWithOps.add((newbody, result))
     let mm = skipTypes(bbody, abstractPtrs)
     if tfFromGeneric notin mm.flags:
       # bug #5479, prevent endless recursions here:
@@ -642,23 +641,6 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
         result.size = -1
         result.n = replaceObjBranches(cl, result.n)
 
-template typeBound(c, newty, oldty, field, info) =
-  let opr = newty.attachedOps[field]
-  if opr != nil and sfFromGeneric notin opr.flags:
-    # '=' needs to be instantiated for generics when the type is constructed:
-    #echo "DESTROY: instantiating ", astToStr(field), " for ", typeToString(oldty)
-    newty.attachedOps[field] = c.instTypeBoundOp(c, opr, oldty, info, attachedAsgn, 1)
-
-proc instAllTypeBoundOp*(c: PContext, info: TLineInfo) =
-  var i = 0
-  while i < c.typesWithOps.len:
-    let (newty, oldty) = c.typesWithOps[i]
-    typeBound(c, newty, oldty, attachedDestructor, info)
-    typeBound(c, newty, oldty, attachedSink, info)
-    typeBound(c, newty, oldty, attachedAsgn, info)
-    inc i
-  setLen(c.typesWithOps, 0)
-
 proc initTypeVars*(p: PContext, typeMap: LayeredIdTable, info: TLineInfo;
                    owner: PSym): TReplTypeVars =
   initIdTable(result.symMap)
diff --git a/compiler/transf.nim b/compiler/transf.nim
index e9ab6b47d..daf223106 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -791,7 +791,7 @@ proc transformCall(c: PTransf, n: PNode): PNode =
         while (j < n.len):
           let b = transform(c, n[j])
           if not isConstExpr(b): break
-          a = evalOp(op.magic, n, a, b, nil, c.graph)
+          a = evalOp(op.magic, n, a, b, nil, c.idgen, c.graph)
           inc(j)
       result.add(a)
     if result.len == 2: result = result[1]
@@ -869,7 +869,7 @@ proc commonOptimizations*(g: ModuleGraph; idgen: IdGenerator; c: PSym, n: PNode)
         while j < args.len:
           let b = args[j]
           if not isConstExpr(b): break
-          a = evalOp(op.magic, result, a, b, nil, g)
+          a = evalOp(op.magic, result, a, b, nil, idgen, g)
           inc(j)
       result.add(a)
     if result.len == 2: result = result[1]