summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/aliases.nim4
-rw-r--r--compiler/ast.nim39
-rw-r--r--compiler/astalgo.nim8
-rw-r--r--compiler/ccgcalls.nim18
-rw-r--r--compiler/ccgexprs.nim194
-rw-r--r--compiler/ccgliterals.nim6
-rw-r--r--compiler/ccgmerge.nim34
-rw-r--r--compiler/ccgstmts.nim53
-rw-r--r--compiler/ccgthreadvars.nim12
-rw-r--r--compiler/ccgtrav.nim20
-rw-r--r--compiler/ccgtypes.nim70
-rw-r--r--compiler/ccgutils.nim2
-rw-r--r--compiler/cgen.nim226
-rw-r--r--compiler/cgendata.nim12
-rw-r--r--compiler/cgmeth.nim45
-rw-r--r--compiler/closureiters.nim150
-rw-r--r--compiler/commands.nim828
-rw-r--r--compiler/condsyms.nim71
-rw-r--r--compiler/configuration.nim360
-rw-r--r--compiler/depends.nim6
-rw-r--r--compiler/destroyer.nim49
-rw-r--r--compiler/dfa.nim18
-rw-r--r--compiler/docgen.nim231
-rw-r--r--compiler/docgen2.nim6
-rw-r--r--compiler/evaltempl.nim30
-rw-r--r--compiler/extccomp.nim388
-rw-r--r--compiler/filter_tmpl.nim27
-rw-r--r--compiler/filters.nim43
-rw-r--r--compiler/gorgeimpl.nim4
-rw-r--r--compiler/guards.nim240
-rw-r--r--compiler/hlo.nim18
-rw-r--r--compiler/idgen.nim12
-rw-r--r--compiler/importer.nim43
-rw-r--r--compiler/jsgen.nim161
-rw-r--r--compiler/jstypes.nim14
-rw-r--r--compiler/lambdalifting.nim203
-rw-r--r--compiler/lexer.nim83
-rw-r--r--compiler/liftlocals.nim6
-rw-r--r--compiler/lookups.nim117
-rw-r--r--compiler/lowerings.nim168
-rw-r--r--compiler/magicsys.nim184
-rw-r--r--compiler/main.nim234
-rw-r--r--compiler/modulegraphs.nim18
-rw-r--r--compiler/modulepaths.nim28
-rw-r--r--compiler/modules.nim46
-rw-r--r--compiler/msgs.nim747
-rw-r--r--compiler/nim.nim89
-rw-r--r--compiler/nimblecmd.nim33
-rw-r--r--compiler/nimconf.nim137
-rw-r--r--compiler/nimfix/nimfix.nim2
-rw-r--r--compiler/nimfix/pretty.nim23
-rw-r--r--compiler/nimsets.nim55
-rw-r--r--compiler/nversion.nim3
-rw-r--r--compiler/options.nim403
-rw-r--r--compiler/packagehandling.nim23
-rw-r--r--compiler/parampatterns.nim53
-rw-r--r--compiler/parser.nim43
-rw-r--r--compiler/passaux.nim18
-rw-r--r--compiler/passes.nim24
-rw-r--r--compiler/patterns.nim4
-rw-r--r--compiler/plugins/itersgen.nim10
-rw-r--r--compiler/pragmas.nim473
-rw-r--r--compiler/procfind.nim14
-rw-r--r--compiler/renderer.nim22
-rw-r--r--compiler/reorder.nim13
-rw-r--r--compiler/rodread.nim133
-rw-r--r--compiler/rodwrite.nim51
-rw-r--r--compiler/scriptconfig.nim64
-rw-r--r--compiler/sem.nim134
-rw-r--r--compiler/semasgn.nim52
-rw-r--r--compiler/semcall.nim61
-rw-r--r--compiler/semdata.nim53
-rw-r--r--compiler/semexprs.nim469
-rw-r--r--compiler/semfields.nim27
-rw-r--r--compiler/semfold.nim512
-rw-r--r--compiler/semgnrc.nim82
-rw-r--r--compiler/seminst.nim27
-rw-r--r--compiler/semmacrosanity.nim36
-rw-r--r--compiler/semmagic.nim62
-rw-r--r--compiler/semobjconstr.nim80
-rw-r--r--compiler/semparallel.nim128
-rw-r--r--compiler/sempass2.nim211
-rw-r--r--compiler/semstmts.nim423
-rw-r--r--compiler/semtempl.nim77
-rw-r--r--compiler/semtypes.nim319
-rw-r--r--compiler/semtypinst.nim43
-rw-r--r--compiler/service.nim14
-rw-r--r--compiler/sigmatch.nim90
-rw-r--r--compiler/suggest.nim102
-rw-r--r--compiler/syntaxes.nim40
-rw-r--r--compiler/transf.nim109
-rw-r--r--compiler/types.nim69
-rw-r--r--compiler/typesrenderer.nim7
-rw-r--r--compiler/vm.nim228
-rw-r--r--compiler/vmdef.nim9
-rw-r--r--compiler/vmdeps.nim10
-rw-r--r--compiler/vmgen.nim204
-rw-r--r--compiler/vmmarshal.nim73
-rw-r--r--compiler/vmops.nim16
-rw-r--r--compiler/writetracking.nim12
100 files changed, 5403 insertions, 5342 deletions
diff --git a/compiler/aliases.nim b/compiler/aliases.nim
index 490ac987a..f79210dd7 100644
--- a/compiler/aliases.nim
+++ b/compiler/aliases.nim
@@ -34,10 +34,10 @@ proc isPartOfAux(n: PNode, b: PType, marker: var IntSet): TAnalysisResult =
       of nkOfBranch, nkElse:
         result = isPartOfAux(lastSon(n.sons[i]), b, marker)
         if result == arYes: return
-      else: internalError("isPartOfAux(record case branch)")
+      else: discard "isPartOfAux(record case branch)"
   of nkSym:
     result = isPartOfAux(n.sym.typ, b, marker)
-  else: internalError(n.info, "isPartOfAux()")
+  else: discard
 
 proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult =
   result = arNo
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 2cace380d..5a84b2b02 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -734,7 +734,7 @@ type
     locOther                  # location is something other
   TLocFlag* = enum
     lfIndirect,               # backend introduced a pointer
-    lfFullExternalName, # only used when 'gCmd == cmdPretty': Indicates
+    lfFullExternalName, # only used when 'conf.cmd == cmdPretty': Indicates
       # that the symbol has been imported via 'importc: "fullname"' and
       # no format string.
     lfNoDeepCopy,             # no need for a deep copy
@@ -1078,14 +1078,14 @@ template previouslyInferred*(t: PType): PType =
   if t.sons.len > 1: t.lastSon else: nil
 
 proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
-             info: TLineInfo): PSym =
+             info: TLineInfo; options: TOptions = {}): PSym =
   # generates a symbol and initializes the hash field too
   new(result)
   result.name = name
   result.kind = symKind
   result.flags = {}
   result.info = info
-  result.options = gOptions
+  result.options = options
   result.owner = owner
   result.offset = -1
   result.id = getID()
@@ -1095,7 +1095,7 @@ proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
   #  writeStacktrace()
   #  MessageOut(name.s & " has id: " & toString(result.id))
 
-var emptyNode* = newNode(nkEmpty)
+var emptyNode* = newNode(nkEmpty) # XXX global variable here!
 # There is a single empty node that is shared! Do not overwrite it!
 
 proc isMetaType*(t: PType): bool =
@@ -1325,7 +1325,7 @@ proc copyType*(t: PType, owner: PSym, keepId: bool): PType =
 proc exactReplica*(t: PType): PType = copyType(t, t.owner, true)
 
 proc copySym*(s: PSym, keepId: bool = false): PSym =
-  result = newSym(s.kind, s.name, s.owner, s.info)
+  result = newSym(s.kind, s.name, s.owner, s.info, s.options)
   #result.ast = nil            # BUGFIX; was: s.ast which made problems
   result.typ = s.typ
   if keepId:
@@ -1344,8 +1344,9 @@ proc copySym*(s: PSym, keepId: bool = false): PSym =
   if result.kind in {skVar, skLet, skField}:
     result.guard = s.guard
 
-proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym =
-  result = newSym(s.kind, newIdent, s.owner, info)
+proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo;
+                        options: TOptions): PSym =
+  result = newSym(s.kind, newIdent, s.owner, info, options)
   # keep ID!
   result.ast = s.ast
   result.id = s.id
@@ -1564,15 +1565,17 @@ proc getInt*(a: PNode): BiggestInt =
   case a.kind
   of nkCharLit..nkUInt64Lit: result = a.intVal
   else:
-    internalError(a.info, "getInt")
-    result = 0
+    #internalError(a.info, "getInt")
+    doAssert false, "getInt"
+    #result = 0
 
 proc getFloat*(a: PNode): BiggestFloat =
   case a.kind
   of nkFloatLiterals: result = a.floatVal
   else:
-    internalError(a.info, "getFloat")
-    result = 0.0
+    doAssert false, "getFloat"
+    #internalError(a.info, "getFloat")
+    #result = 0.0
 
 proc getStr*(a: PNode): string =
   case a.kind
@@ -1581,16 +1584,18 @@ proc getStr*(a: PNode): string =
     # let's hope this fixes more problems than it creates:
     result = nil
   else:
-    internalError(a.info, "getStr")
-    result = ""
+    doAssert false, "getStr"
+    #internalError(a.info, "getStr")
+    #result = ""
 
 proc getStrOrChar*(a: PNode): string =
   case a.kind
   of nkStrLit..nkTripleStrLit: result = a.strVal
   of nkCharLit..nkUInt64Lit: result = $chr(int(a.intVal))
   else:
-    internalError(a.info, "getStrOrChar")
-    result = ""
+    doAssert false, "getStrOrChar"
+    #internalError(a.info, "getStrOrChar")
+    #result = ""
 
 proc isGenericRoutine*(s: PSym): bool =
   case s.kind
@@ -1689,9 +1694,9 @@ proc isException*(t: PType): bool =
     base = base.lastSon
   return false
 
-proc isImportedException*(t: PType): bool =
+proc isImportedException*(t: PType; conf: ConfigRef): bool =
   assert(t != nil)
-  if optNoCppExceptions in gGlobalOptions:
+  if optNoCppExceptions in conf.globalOptions:
     return false
 
   let base = t.skipTypes({tyAlias, tyPtr, tyDistinct, tyGenericInst})
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index a35fa4fbb..d98a42b34 100644
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -180,7 +180,7 @@ proc lookupInRecord(n: PNode, field: PIdent): PSym =
       result = lookupInRecord(n.sons[i], field)
       if result != nil: return
   of nkRecCase:
-    if (n.sons[0].kind != nkSym): internalError(n.info, "lookupInRecord")
+    if (n.sons[0].kind != nkSym): return nil
     result = lookupInRecord(n.sons[0], field)
     if result != nil: return
     for i in countup(1, sonsLen(n) - 1):
@@ -188,10 +188,10 @@ proc lookupInRecord(n: PNode, field: PIdent): PSym =
       of nkOfBranch, nkElse:
         result = lookupInRecord(lastSon(n.sons[i]), field)
         if result != nil: return
-      else: internalError(n.info, "lookupInRecord(record case branch)")
+      else: return nil
   of nkSym:
     if n.sym.name.id == field.id: result = n.sym
-  else: internalError(n.info, "lookupInRecord()")
+  else: return nil
 
 proc getModule(s: PSym): PSym =
   result = s
@@ -203,7 +203,7 @@ proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
     if list.sons[i].kind == nkSym:
       result = list.sons[i].sym
       if result.name.id == ident.id: return
-    else: internalError(list.info, "getSymFromList")
+    else: return nil
   result = nil
 
 proc hashNode(p: RootRef): Hash =
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 2ddc88509..7d355db5f 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -116,7 +116,7 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
       else:
         result = "$1->data+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)]
     else:
-      internalError("openArrayLoc: " & typeToString(a.t))
+      internalError(p.config, "openArrayLoc: " & typeToString(a.t))
   else:
     initLocExpr(p, n, a)
     case skipTypes(a.t, abstractVar).kind
@@ -137,8 +137,8 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
       of tyArray:
         result = "$1, $2" % [rdLoc(a), rope(lengthOrd(lastSon(a.t)))]
       else:
-        internalError("openArrayLoc: " & typeToString(a.t))
-    else: internalError("openArrayLoc: " & typeToString(a.t))
+        internalError(p.config, "openArrayLoc: " & typeToString(a.t))
+    else: internalError(p.config, "openArrayLoc: " & typeToString(a.t))
 
 proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} =
   var a: TLoc
@@ -273,7 +273,7 @@ proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
       result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym)
   else:
     if tfVarargs notin typ.flags:
-      localError(ri.info, "wrong argument count")
+      localError(p.config, ri.info, "wrong argument count")
       result = nil
     else:
       result = genArgNoParam(p, ri.sons[i])
@@ -337,7 +337,7 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
   # for better or worse c2nim translates the 'this' argument to a 'var T'.
   # However manual wrappers may also use 'ptr T'. In any case we support both
   # for convenience.
-  internalAssert i < sonsLen(typ)
+  internalAssert p.config, i < sonsLen(typ)
   assert(typ.n.sons[i].kind == nkSym)
   # if the parameter is lying (tyVar) and thus we required an additional deref,
   # skip the deref:
@@ -394,7 +394,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope =
             result.add genOtherArg(p, ri, k, typ)
           result.add(~")")
         else:
-          localError(ri.info, "call expression expected for C++ pattern")
+          localError(p.config, ri.info, "call expression expected for C++ pattern")
         inc i
       elif pat[i+1] == '.':
         result.add genThisArg(p, ri, j, typ)
@@ -432,7 +432,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
   assert(sonsLen(typ) == sonsLen(typ.n))
   # don't call '$' here for efficiency:
   let pat = ri.sons[0].sym.loc.r.data
-  internalAssert pat != nil
+  internalAssert p.config, pat != nil
   if pat.contains({'#', '(', '@', '\''}):
     var pl = genPatternCall(p, ri, pat, typ)
     # simpler version of 'fixupCall' that works with the pl+params combination:
@@ -481,7 +481,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
 
   # don't call '$' here for efficiency:
   let pat = ri.sons[0].sym.loc.r.data
-  internalAssert pat != nil
+  internalAssert p.config, pat != nil
   var start = 3
   if ' ' in pat:
     start = 1
@@ -501,7 +501,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
   for i in countup(start, length-1):
     assert(sonsLen(typ) == sonsLen(typ.n))
     if i >= sonsLen(typ):
-      internalError(ri.info, "varargs for objective C method?")
+      internalError(p.config, ri.info, "varargs for objective C method?")
     assert(typ.n.sons[i].kind == nkSym)
     var param = typ.n.sons[i].sym
     add(pl, ~" ")
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 5b3f6c3d2..352402e0e 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -13,7 +13,7 @@
 
 proc int64Literal(i: BiggestInt): Rope =
   if i > low(int64):
-    result = rfmt(nil, "IL64($1)", rope(i))
+    result = "IL64($1)" % [rope(i)]
   else:
     result = ~"(IL64(-9223372036854775807) - IL64(1))"
 
@@ -26,12 +26,12 @@ proc intLiteral(i: BiggestInt): Rope =
     # Nim has the same bug for the same reasons :-)
     result = ~"(-2147483647 -1)"
   elif i > low(int64):
-    result = rfmt(nil, "IL64($1)", rope(i))
+    result = "IL64($1)" % [rope(i)]
   else:
     result = ~"(IL64(-9223372036854775807) - IL64(1))"
 
 proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
-  if ty == nil: internalError(n.info, "genLiteral: ty is nil")
+  if ty == nil: internalError(p.config, n.info, "genLiteral: ty is nil")
   case n.kind
   of nkCharLit..nkUInt64Lit:
     case skipTypes(ty, abstractVarRange).kind
@@ -76,7 +76,7 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
   of nkFloat32Lit:
     result = rope(n.floatVal.toStrMaxPrecision("f"))
   else:
-    internalError(n.info, "genLiteral(" & $n.kind & ')')
+    internalError(p.config, n.info, "genLiteral(" & $n.kind & ')')
     result = nil
 
 proc genLiteral(p: BProc, n: PNode): Rope =
@@ -145,7 +145,7 @@ proc getStorageLoc(n: PNode): TStorageLoc =
     of tyVar, tyLent: result = OnUnknown
     of tyPtr: result = OnStack
     of tyRef: result = OnHeap
-    else: internalError(n.info, "getStorageLoc")
+    else: doAssert(false, "getStorageLoc")
   of nkBracketExpr, nkDotExpr, nkObjDownConv, nkObjUpConv:
     result = getStorageLoc(n.sons[0])
   else: result = OnUnknown
@@ -164,7 +164,7 @@ proc canMove(n: PNode): bool =
   #  result = false
 
 proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
-  if dest.storage == OnStack or not usesNativeGC():
+  if dest.storage == OnStack or not usesNativeGC(p.config):
     linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
   elif dest.storage == OnHeap:
     # location is on heap
@@ -256,7 +256,7 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
   # (for objects, etc.):
   if needToCopy notin flags or
       tfShallow in skipTypes(dest.t, abstractVarRange).flags:
-    if dest.storage == OnStack or not usesNativeGC():
+    if dest.storage == OnStack or not usesNativeGC(p.config):
       useStringh(p.module)
       linefmt(p, cpsStmts,
            "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
@@ -290,7 +290,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
     if (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode):
       genRefAssign(p, dest, src, flags)
     else:
-      if dest.storage == OnStack or not usesNativeGC():
+      if dest.storage == OnStack or not usesNativeGC(p.config):
         linefmt(p, cpsStmts, "$1 = #copyString($2);$n", dest.rdLoc, src.rdLoc)
       elif dest.storage == OnHeap:
         # we use a temporary to care for the dreaded self assignment:
@@ -326,7 +326,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
     elif needsComplexAssignment(ty):
       if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4:
         discard getTypeDesc(p.module, ty)
-        internalAssert ty.n != nil
+        internalAssert p.config, ty.n != nil
         genOptAsgnObject(p, dest, src, flags, ty.n, ty)
       else:
         genGenericAsgn(p, dest, src, flags)
@@ -363,7 +363,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
   of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString,
      tyInt..tyUInt64, tyRange, tyVar, tyLent:
     linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
-  else: internalError("genAssignment: " & $ty.kind)
+  else: internalError(p.config, "genAssignment: " & $ty.kind)
 
   if optMemTracker in p.options and dest.storage in {OnHeap, OnUnknown}:
     #writeStackTrace()
@@ -409,7 +409,7 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) =
   of tyPointer, tyChar, tyBool, tyEnum, tyCString,
      tyInt..tyUInt64, tyRange, tyVar, tyLent:
     linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
-  else: internalError("genDeepCopy: " & $ty.kind)
+  else: internalError(p.config, "genDeepCopy: " & $ty.kind)
 
 proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc) =
   if d.k != locNone:
@@ -450,14 +450,14 @@ proc putIntoDest(p: BProc, d: var TLoc, n: PNode, r: Rope; s=OnUnknown) =
 
 proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
   var a, b: TLoc
-  if d.k != locNone: internalError(e.info, "binaryStmt")
+  if d.k != locNone: internalError(p.config, e.info, "binaryStmt")
   initLocExpr(p, e.sons[1], a)
   initLocExpr(p, e.sons[2], b)
   lineCg(p, cpsStmts, frmt, rdLoc(a), rdLoc(b))
 
 proc unaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
   var a: TLoc
-  if d.k != locNone: internalError(e.info, "unaryStmt")
+  if d.k != locNone: internalError(p.config, e.info, "unaryStmt")
   initLocExpr(p, e.sons[1], a)
   lineCg(p, cpsStmts, frmt, [rdLoc(a)])
 
@@ -701,7 +701,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
       of tyPtr:
         d.storage = OnUnknown         # BUGFIX!
       else:
-        internalError(e.info, "genDeref " & $typ.kind)
+        internalError(p.config, e.info, "genDeref " & $typ.kind)
     elif p.module.compileToCpp:
       if typ.kind == tyVar and tfVarIsPtr notin typ.flags and
            e.kind == nkHiddenDeref:
@@ -736,7 +736,7 @@ template inheritLocation(d: var TLoc, a: TLoc) =
 
 proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc) =
   initLocExpr(p, e.sons[0], a)
-  if e.sons[1].kind != nkSym: internalError(e.info, "genRecordFieldAux")
+  if e.sons[1].kind != nkSym: internalError(p.config, e.info, "genRecordFieldAux")
   d.inheritLocation(a)
   discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
 
@@ -752,7 +752,7 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
   var r = rdLoc(a)
   case e.sons[1].kind
   of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal)
-  else: internalError(e.info, "genTupleElem")
+  else: internalError(p.config, e.info, "genTupleElem")
   addf(r, ".Field$1", [rope(i)])
   putIntoDest(p, d, e, r, a.storage)
 
@@ -769,7 +769,7 @@ proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope;
       break
     if not p.module.compileToCpp: add(r, ".Sup")
     ty = ty.sons[0]
-  if result == nil: internalError(field.info, "genCheckedRecordField")
+  if result == nil: internalError(p.config, field.info, "genCheckedRecordField")
 
 proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
   var a: TLoc
@@ -786,7 +786,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
     var rtyp: PType
     let field = lookupFieldAgain(p, ty, f, r, addr rtyp)
     if field.loc.r == nil and rtyp != nil: fillObjectFields(p.module, rtyp)
-    if field.loc.r == nil: internalError(e.info, "genRecordField 3 " & typeToString(ty))
+    if field.loc.r == nil: internalError(p.config, e.info, "genRecordField 3 " & typeToString(ty))
     addf(r, ".$1", [field.loc.r])
     putIntoDest(p, d, e, r, a.storage)
 
@@ -832,9 +832,9 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
     let field = lookupFieldAgain(p, ty, f, r)
     if field.loc.r == nil: fillObjectFields(p.module, ty)
     if field.loc.r == nil:
-      internalError(e.info, "genCheckedRecordField") # generate the checks:
+      internalError(p.config, e.info, "genCheckedRecordField") # generate the checks:
     genFieldCheck(p, e, r, field)
-    add(r, rfmt(nil, ".$1", field.loc.r))
+    add(r, ropecg(p.module, ".$1", field.loc.r))
     putIntoDest(p, d, e.sons[0], r, a.storage)
   else:
     genRecordField(p, e.sons[0], d)
@@ -859,10 +859,10 @@ proc genArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
     else:
       let idx = getOrdValue(y)
       if idx < firstOrd(ty) or idx > lastOrd(ty):
-        localError(x.info, errIndexOutOfBounds)
+        localError(p.config, x.info, "index out of bounds")
   d.inheritLocation(a)
   putIntoDest(p, d, n,
-              rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first), a.storage)
+              ropecg(p.module, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first), a.storage)
 
 proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) =
   var a, b: TLoc
@@ -871,7 +871,7 @@ proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) =
   var ty = skipTypes(a.t, abstractVarRange)
   inheritLocation(d, a)
   putIntoDest(p, d, n,
-              rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
+              ropecg(p.module, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
 
 proc genIndexCheck(p: BProc; arr, idx: TLoc) =
   let ty = skipTypes(arr.t, abstractVarRange)
@@ -899,7 +899,7 @@ proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
             rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``!
   inheritLocation(d, a)
   putIntoDest(p, d, n,
-              rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
+              ropecg(p.module, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
 
 proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
   var a, b: TLoc
@@ -919,9 +919,9 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
               rdLoc(b), rdLoc(a), lenField(p))
   if d.k == locNone: d.storage = OnHeap
   if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
-    a.r = rfmt(nil, "(*$1)", a.r)
+    a.r = ropecg(p.module, "(*$1)", a.r)
   putIntoDest(p, d, n,
-              rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
+              ropecg(p.module, "$1->data[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
 
 proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
   var ty = skipTypes(n.sons[0].typ, abstractVarRange + tyUserTypeClasses)
@@ -932,7 +932,7 @@ proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
   of tySequence, tyString: genSeqElem(p, n, n.sons[0], n.sons[1], d)
   of tyCString: genCStringElem(p, n, n.sons[0], n.sons[1], d)
   of tyTuple: genTupleElem(p, n, d)
-  else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
+  else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
 
 proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
   # how to generate code?
@@ -977,7 +977,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
 proc genEcho(p: BProc, n: PNode) =
   # this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
   # is threadsafe.
-  internalAssert n.kind == nkBracket
+  internalAssert p.config, n.kind == nkBracket
   if platform.targetOS == osGenode:
     # bypass libc and print directly to the Genode LOG session
     var args: Rope = nil
@@ -1003,8 +1003,8 @@ proc genEcho(p: BProc, n: PNode) =
               makeCString(repeat("%s", n.len) & tnl), args)
       linefmt(p, cpsStmts, "fflush(stdout);$n")
 
-proc gcUsage(n: PNode) =
-  if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree)
+proc gcUsage(conf: ConfigRef; n: PNode) =
+  if conf.selectedGC == gcNone: message(conf, n.info, warnGcMem, n.renderTree)
 
 proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
   #   <Nim code>
@@ -1033,20 +1033,20 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
     initLocExpr(p, e.sons[i + 1], a)
     if skipTypes(e.sons[i + 1].typ, abstractVarRange).kind == tyChar:
       inc(L)
-      add(appends, rfmt(p.module, "#appendChar($1, $2);$n", tmp.r, rdLoc(a)))
+      add(appends, ropecg(p.module, "#appendChar($1, $2);$n", tmp.r, rdLoc(a)))
     else:
       if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
         inc(L, len(e.sons[i + 1].strVal))
       else:
         addf(lens, "($1 ? $1->$2 : 0) + ", [rdLoc(a), lenField(p)])
-      add(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a)))
+      add(appends, ropecg(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a)))
   linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, rope(L))
   add(p.s(cpsStmts), appends)
   if d.k == locNone:
     d = tmp
   else:
     genAssignment(p, d, tmp, {}) # no need for deep copying
-  gcUsage(e)
+  gcUsage(p.config, e)
 
 proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
   #  <Nim code>
@@ -1071,19 +1071,19 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
     initLocExpr(p, e.sons[i + 2], a)
     if skipTypes(e.sons[i + 2].typ, abstractVarRange).kind == tyChar:
       inc(L)
-      add(appends, rfmt(p.module, "#appendChar($1, $2);$n",
+      add(appends, ropecg(p.module, "#appendChar($1, $2);$n",
                         rdLoc(dest), rdLoc(a)))
     else:
       if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
         inc(L, len(e.sons[i + 2].strVal))
       else:
         addf(lens, "($1 ? $1->$2 : 0) + ", [rdLoc(a), lenField(p)])
-      add(appends, rfmt(p.module, "#appendString($1, $2);$n",
+      add(appends, ropecg(p.module, "#appendString($1, $2);$n",
                         rdLoc(dest), rdLoc(a)))
   linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n",
           rdLoc(dest), lens, rope(L))
   add(p.s(cpsStmts), appends)
-  gcUsage(e)
+  gcUsage(p.config, e)
 
 proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
   # seq &= x  -->
@@ -1106,9 +1106,9 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
   initLoc(dest, locExpr, e.sons[2], OnHeap)
   getIntTemp(p, tmpL)
   lineCg(p, cpsStmts, "$1 = $2->$3++;$n", tmpL.r, rdLoc(a), lenField(p))
-  dest.r = rfmt(nil, "$1->data[$2]", rdLoc(a), tmpL.r)
+  dest.r = ropecg(p.module, "$1->data[$2]", rdLoc(a), tmpL.r)
   genAssignment(p, dest, b, {needToCopy, afDestIsNil})
-  gcUsage(e)
+  gcUsage(p.config, e)
 
 proc genReset(p: BProc, n: PNode) =
   var a: TLoc
@@ -1131,7 +1131,7 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
   let args = [getTypeDesc(p.module, typ),
               genTypeInfo(p.module, typ, a.lode.info),
               sizeExpr]
-  if a.storage == OnHeap and usesNativeGC():
+  if a.storage == OnHeap and usesNativeGC(p.config):
     # use newObjRC1 as an optimization
     if canFormAcycle(a.t):
       linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", a.rdLoc)
@@ -1154,7 +1154,7 @@ proc genNew(p: BProc, e: PNode) =
     rawGenNew(p, a, se.rdLoc)
   else:
     rawGenNew(p, a, nil)
-  gcUsage(e)
+  gcUsage(p.config, e)
 
 proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) =
   let seqtype = skipTypes(dest.t, abstractVarRange)
@@ -1162,7 +1162,7 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) =
               genTypeInfo(p.module, seqtype, dest.lode.info), length]
   var call: TLoc
   initLoc(call, locExpr, dest.lode, OnHeap)
-  if dest.storage == OnHeap and usesNativeGC():
+  if dest.storage == OnHeap and usesNativeGC(p.config):
     if canFormAcycle(dest.t):
       linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", dest.rdLoc)
     else:
@@ -1178,7 +1178,7 @@ proc genNewSeq(p: BProc, e: PNode) =
   initLocExpr(p, e.sons[1], a)
   initLocExpr(p, e.sons[2], b)
   genNewSeqAux(p, a, b.rdLoc)
-  gcUsage(e)
+  gcUsage(p.config, e)
 
 proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
   let seqtype = skipTypes(e.typ, abstractVarRange)
@@ -1188,7 +1188,7 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
               "($1)#nimNewSeqOfCap($2, $3)", [
               getTypeDesc(p.module, seqtype),
               genTypeInfo(p.module, seqtype, e.info), a.rdLoc]))
-  gcUsage(e)
+  gcUsage(p.config, e)
 
 proc genConstExpr(p: BProc, n: PNode): Rope
 proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
@@ -1230,7 +1230,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
       rawGenNew(p, tmp, nil)
       t = t.lastSon.skipTypes(abstractInst)
       r = "(*$1)" % [r]
-      gcUsage(e)
+      gcUsage(p.config, e)
     else:
       constructLoc(p, tmp)
   else:
@@ -1244,7 +1244,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
     tmp2.r = r
     let field = lookupFieldAgain(p, ty, it.sons[0].sym, tmp2.r)
     if field.loc.r == nil: fillObjectFields(p.module, ty)
-    if field.loc.r == nil: internalError(e.info, "genObjConstr")
+    if field.loc.r == nil: internalError(p.config, e.info, "genObjConstr")
     if it.len == 3 and optFieldCheck in p.options:
       genFieldCheck(p, it.sons[2], r, field)
     add(tmp2.r, ".")
@@ -1280,10 +1280,10 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
   genNewSeqAux(p, dest[], intLiteral(sonsLen(n)))
   for i in countup(0, sonsLen(n) - 1):
     initLoc(arr, locExpr, n[i], OnHeap)
-    arr.r = rfmt(nil, "$1->data[$2]", rdLoc(dest[]), intLiteral(i))
+    arr.r = ropecg(p.module, "$1->data[$2]", rdLoc(dest[]), intLiteral(i))
     arr.storage = OnHeap            # we know that sequences are on the heap
     expr(p, n[i], arr)
-  gcUsage(n)
+  gcUsage(p.config, n)
   if doesAlias:
     if d.k == locNone:
       d = tmp
@@ -1306,21 +1306,21 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
   if L < 10:
     for i in countup(0, L - 1):
       initLoc(elem, locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap)
-      elem.r = rfmt(nil, "$1->data[$2]", rdLoc(d), intLiteral(i))
+      elem.r = ropecg(p.module, "$1->data[$2]", rdLoc(d), intLiteral(i))
       elem.storage = OnHeap # we know that sequences are on the heap
       initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.sons[1].typ, abstractInst)), a.storage)
-      arr.r = rfmt(nil, "$1[$2]", rdLoc(a), intLiteral(i))
+      arr.r = ropecg(p.module, "$1[$2]", rdLoc(a), intLiteral(i))
       genAssignment(p, elem, arr, {afDestIsNil, needToCopy})
   else:
     var i: TLoc
-    getTemp(p, getSysType(tyInt), i)
+    getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i)
     let oldCode = p.s(cpsStmts)
     linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",  i.r, L.rope)
     initLoc(elem, locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap)
-    elem.r = rfmt(nil, "$1->data[$2]", rdLoc(d), rdLoc(i))
+    elem.r = ropecg(p.module, "$1->data[$2]", rdLoc(d), rdLoc(i))
     elem.storage = OnHeap # we know that sequences are on the heap
     initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.sons[1].typ, abstractInst)), a.storage)
-    arr.r = rfmt(nil, "$1[$2]", rdLoc(a), rdLoc(i))
+    arr.r = ropecg(p.module, "$1[$2]", rdLoc(a), rdLoc(i))
     genAssignment(p, elem, arr, {afDestIsNil, needToCopy})
     lineF(p, cpsStmts, "}$n", [])
 
@@ -1342,7 +1342,7 @@ proc genNewFinalize(p: BProc, e: PNode) =
   genAssignment(p, a, b, {})  # set the object type:
   bt = skipTypes(refType.lastSon, abstractRange)
   genObjectInit(p, cpsStmts, bt, a, false)
-  gcUsage(e)
+  gcUsage(p.config, e)
 
 proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope =
   # unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we
@@ -1356,10 +1356,10 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope =
     inc p.module.labels
     let cache = "Nim_OfCheck_CACHE" & p.module.labels.rope
     addf(p.module.s[cfsVars], "static TNimType* $#[2];$n", [cache])
-    result = rfmt(p.module, "#isObjWithCache($#.m_type, $#, $#)", a, ti, cache)
+    result = ropecg(p.module, "#isObjWithCache($#.m_type, $#, $#)", a, ti, cache)
   when false:
     # former version:
-    result = rfmt(p.module, "#isObj($1.m_type, $2)",
+    result = ropecg(p.module, "#isObj($1.m_type, $2)",
                   a, genTypeInfo(p.module, dest, info))
 
 proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
@@ -1372,7 +1372,7 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
   while t.kind in {tyVar, tyLent, tyPtr, tyRef}:
     if t.kind notin {tyVar, tyLent}: nilCheck = r
     if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp:
-      r = rfmt(nil, "(*$1)", r)
+      r = ropecg(p.module, "(*$1)", r)
     t = skipTypes(t.lastSon, typedescInst)
   discard getTypeDesc(p.module, t)
   if not p.module.compileToCpp:
@@ -1380,12 +1380,12 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
       add(r, ~".Sup")
       t = skipTypes(t.sons[0], skipPtrs)
   if isObjLackingTypeField(t):
-    globalError(x.info, errGenerated,
+    globalError(p.config, x.info,
       "no 'of' operator available for pure objects")
   if nilCheck != nil:
-    r = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r, x.info))
+    r = ropecg(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r, x.info))
   else:
-    r = rfmt(p.module, "($1)", genOfHelper(p, dest, r, x.info))
+    r = ropecg(p.module, "($1)", genOfHelper(p, dest, r, x.info))
   putIntoDest(p, d, x, r, a.storage)
 
 proc genOf(p: BProc, n: PNode, d: var TLoc) =
@@ -1425,7 +1425,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
     of tyArray:
       putIntoDest(p, b, e,
                   "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))], a.storage)
-    else: internalError(e.sons[0].info, "genRepr()")
+    else: internalError(p.config, e.sons[0].info, "genRepr()")
     putIntoDest(p, d, e,
         ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b),
         genTypeInfo(p.module, elemType(t), e.info)]), a.storage)
@@ -1434,12 +1434,12 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
                 ropecg(p.module, "#reprAny($1, $2)", [
                 rdLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage)
   of tyEmpty, tyVoid:
-    localError(e.info, "'repr' doesn't support 'void' type")
+    localError(p.config, e.info, "'repr' doesn't support 'void' type")
   else:
     putIntoDest(p, d, e, ropecg(p.module, "#reprAny($1, $2)",
                               [addrLoc(a), genTypeInfo(p.module, t, e.info)]),
                                a.storage)
-  gcUsage(e)
+  gcUsage(p.config, e)
 
 proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) =
   let t = e.sons[1].typ
@@ -1451,7 +1451,7 @@ proc genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
   a.r = ropecg(p.module, frmt, [rdLoc(a)])
   if d.k == locNone: getTemp(p, n.typ, d)
   genAssignment(p, d, a, {})
-  gcUsage(n)
+  gcUsage(p.config, n)
 
 proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   var a = e.sons[1]
@@ -1493,7 +1493,7 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     # YYY: length(sideeffect) is optimized away incorrectly?
     if op == mHigh: putIntoDest(p, d, e, rope(lastOrd(typ)))
     else: putIntoDest(p, d, e, rope(lengthOrd(typ)))
-  else: internalError(e.info, "genArrayLen()")
+  else: internalError(p.config, e.info, "genArrayLen()")
 
 proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
   var a, b: TLoc
@@ -1511,11 +1511,11 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
   lineCg(p, cpsStmts, setLenPattern, [
       rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
       genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)])
-  gcUsage(e)
+  gcUsage(p.config, e)
 
 proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) =
   binaryStmt(p, e, d, "$1 = #setLengthStr($1, $2);$n")
-  gcUsage(e)
+  gcUsage(p.config, e)
 
 proc genSwap(p: BProc, e: PNode, d: var TLoc) =
   # swap(a, b) -->
@@ -1541,7 +1541,7 @@ proc rdSetElemLoc(a: TLoc, setType: PType): Rope =
 proc fewCmps(s: PNode): bool =
   # this function estimates whether it is better to emit code
   # for constructing the set or generating a bunch of comparisons directly
-  if s.kind != nkCurly: internalError(s.info, "fewCmps")
+  if s.kind != nkCurly: return false
   if (getSize(s.typ) <= platform.intSize) and (nfAllConst in s.flags):
     result = false            # it is better to emit the set generation code
   elif elemType(s.typ).kind in {tyInt, tyInt16..tyInt64}:
@@ -1637,17 +1637,17 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     of mSymDiffSet: binaryExpr(p, e, d, "($1 ^ $2)")
     of mInSet:
       genInOp(p, e, d)
-    else: internalError(e.info, "genSetOp()")
+    else: internalError(p.config, e.info, "genSetOp()")
   else:
     case op
     of mIncl: binaryStmtInExcl(p, e, d, "$1[(NU)($2)>>3] |=(1U<<($2&7U));$n")
     of mExcl: binaryStmtInExcl(p, e, d, "$1[(NU)($2)>>3] &= ~(1U<<($2&7U));$n")
     of mCard: unaryExprChar(p, e, d, "#cardSet($1, " & $size & ')')
     of mLtSet, mLeSet:
-      getTemp(p, getSysType(tyInt), i) # our counter
+      getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i) # our counter
       initLocExpr(p, e.sons[1], a)
       initLocExpr(p, e.sons[2], b)
-      if d.k == locNone: getTemp(p, getSysType(tyBool), d)
+      if d.k == locNone: getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyBool), d)
       lineF(p, cpsStmts, lookupOpr[op],
            [rdLoc(i), rope(size), rdLoc(d), rdLoc(a), rdLoc(b)])
     of mEqSet:
@@ -1655,7 +1655,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       binaryExprChar(p, e, d, "(memcmp($1, $2, " & $(size) & ")==0)")
     of mMulSet, mPlusSet, mMinusSet, mSymDiffSet:
       # we inline the simple for loop for better code generation:
-      getTemp(p, getSysType(tyInt), i) # our counter
+      getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i) # our counter
       initLocExpr(p, e.sons[1], a)
       initLocExpr(p, e.sons[2], b)
       if d.k == locNone: getTemp(p, a.t, d)
@@ -1665,7 +1665,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
           rdLoc(i), rope(size), rdLoc(d), rdLoc(a), rdLoc(b),
           rope(lookupOpr[op])])
     of mInSet: genInOp(p, e, d)
-    else: internalError(e.info, "genSetOp")
+    else: internalError(p.config, e.info, "genSetOp")
 
 proc genOrd(p: BProc, e: PNode, d: var TLoc) =
   unaryExprChar(p, e, d, "$1")
@@ -1753,7 +1753,7 @@ proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) =
   putIntoDest(p, d, n,
               ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]),
               a.storage)
-  gcUsage(n)
+  gcUsage(p.config, n)
 
 proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
   var x: TLoc
@@ -1762,11 +1762,11 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
   if a.kind in {nkStrLit..nkTripleStrLit} and a.strVal == "":
     initLocExpr(p, e.sons[2], x)
     putIntoDest(p, d, e,
-      rfmt(nil, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p)))
+      ropecg(p.module, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p)))
   elif b.kind in {nkStrLit..nkTripleStrLit} and b.strVal == "":
     initLocExpr(p, e.sons[1], x)
     putIntoDest(p, d, e,
-      rfmt(nil, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p)))
+      ropecg(p.module, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p)))
   else:
     binaryExpr(p, e, d, "#eqStrings($1, $2)")
 
@@ -1778,7 +1778,7 @@ proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
     assert(e.sons[2].typ != nil)
     initLocExpr(p, e.sons[1], a)
     initLocExpr(p, e.sons[2], b)
-    putIntoDest(p, d, e, rfmt(nil, "(($4)($2) $1 ($4)($3))",
+    putIntoDest(p, d, e, ropecg(p.module, "(($4)($2) $1 ($4)($3))",
                               rope(opr[m]), rdLoc(a), rdLoc(b),
                               getSimpleTypeDesc(p.module, e[1].typ)))
     if optNaNCheck in p.options:
@@ -1887,12 +1887,12 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   of mEcho: genEcho(p, e[1].skipConv)
   of mArrToSeq: genArrToSeq(p, e, d)
   of mNLen..mNError, mSlurp..mQuoteAst:
-    localError(e.info, errXMustBeCompileTime, e.sons[0].sym.name.s)
+    localError(p.config, e.info, strutils.`%`(errXMustBeCompileTime, e.sons[0].sym.name.s))
   of mSpawn:
-    let n = lowerings.wrapProcForSpawn(p.module.module, e, e.typ, nil, nil)
+    let n = lowerings.wrapProcForSpawn(p.module.g.graph, p.module.module, e, e.typ, nil, nil)
     expr(p, n, d)
   of mParallel:
-    let n = semparallel.liftParallel(p.module.module, e)
+    let n = semparallel.liftParallel(p.module.g.graph, p.module.module, e)
     expr(p, n, d)
   of mDeepCopy:
     var a, b: TLoc
@@ -1904,7 +1904,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   else:
     when defined(debugMagics):
       echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind
-    internalError(e.info, "genMagicExpr: " & $op)
+    internalError(p.config, e.info, "genMagicExpr: " & $op)
 
 proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
   # example: { a..b, c, d, e, f..g }
@@ -1924,7 +1924,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
           [rdLoc(d), getTypeDesc(p.module, e.typ)])
       for it in e.sons:
         if it.kind == nkRange:
-          getTemp(p, getSysType(tyInt), idx) # our counter
+          getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), idx) # our counter
           initLocExpr(p, it.sons[0], a)
           initLocExpr(p, it.sons[1], b)
           lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" &
@@ -1940,7 +1940,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
       lineF(p, cpsStmts, "$1 = 0;$n", [rdLoc(d)])
       for it in e.sons:
         if it.kind == nkRange:
-          getTemp(p, getSysType(tyInt), idx) # our counter
+          getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), idx) # our counter
           initLocExpr(p, it.sons[0], a)
           initLocExpr(p, it.sons[1], b)
           lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" &
@@ -1984,7 +1984,7 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) =
     initLocExpr(p, n.sons[0], a)
     initLocExpr(p, n.sons[1], b)
     if n.sons[0].skipConv.kind == nkClosure:
-      internalError(n.info, "closure to closure created")
+      internalError(p.config, n.info, "closure to closure created")
     # tasyncawait.nim breaks with this optimization:
     when false:
       if d.k != locNone:
@@ -2025,7 +2025,7 @@ template genStmtListExprImpl(exprOrStmt) {.dirty.} =
         let theMacro = it[0].sym
         add p.s(cpsStmts), initFrameNoDebug(p, frameName,
            makeCString theMacro.name.s,
-           theMacro.info.quotedFilename, it.info.line.int)
+           quotedFilename(p.config, theMacro.info), it.info.line.int)
     else:
       genStmts(p, it)
   if n.len > 0: exprOrStmt
@@ -2146,11 +2146,11 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
       #if sym.kind == skIterator:
       #  echo renderTree(sym.getBody, {renderIds})
       if sfCompileTime in sym.flags:
-        localError(n.info, "request to generate code for .compileTime proc: " &
+        localError(p.config, n.info, "request to generate code for .compileTime proc: " &
            sym.name.s)
       genProc(p.module, sym)
       if sym.loc.r == nil or sym.loc.lode == nil:
-        internalError(n.info, "expr: proc not init " & sym.name.s)
+        internalError(p.config, n.info, "expr: proc not init " & sym.name.s)
       putLocIntoDest(p, d, sym.loc)
     of skConst:
       if isSimpleConst(sym.typ):
@@ -2168,10 +2168,10 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
       if sym.loc.r == nil or sym.loc.t == nil:
         #echo "FAILED FOR PRCO ", p.prc.name.s
         #echo renderTree(p.prc.ast, {renderIds})
-        internalError n.info, "expr: var not init " & sym.name.s & "_" & $sym.id
+        internalError p.config, n.info, "expr: var not init " & sym.name.s & "_" & $sym.id
       if sfThread in sym.flags:
         accessThreadLocalVar(p, sym)
-        if emulatedThreadVars():
+        if emulatedThreadVars(p.config):
           putIntoDest(p, d, sym.loc.lode, "NimTV_->" & sym.loc.r)
         else:
           putLocIntoDest(p, d, sym.loc)
@@ -2181,16 +2181,16 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
       if sym.loc.r == nil or sym.loc.t == nil:
         #echo "FAILED FOR PRCO ", p.prc.name.s
         #echo renderTree(p.prc.ast, {renderIds})
-        internalError(n.info, "expr: temp not init " & sym.name.s & "_" & $sym.id)
+        internalError(p.config, n.info, "expr: temp not init " & sym.name.s & "_" & $sym.id)
       putLocIntoDest(p, d, sym.loc)
     of skParam:
       if sym.loc.r == nil or sym.loc.t == nil:
         # echo "FAILED FOR PRCO ", p.prc.name.s
         # debug p.prc.typ.n
         # echo renderTree(p.prc.ast, {renderIds})
-        internalError(n.info, "expr: param not init " & sym.name.s & "_" & $sym.id)
+        internalError(p.config, n.info, "expr: param not init " & sym.name.s & "_" & $sym.id)
       putLocIntoDest(p, d, sym.loc)
-    else: internalError(n.info, "expr(" & $sym.kind & "); unknown symbol")
+    else: internalError(p.config, n.info, "expr(" & $sym.kind & "); unknown symbol")
   of nkNilLit:
     if not isEmptyType(n.typ):
       putIntoDest(p, d, n, genLiteral(p, n))
@@ -2259,7 +2259,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
     var sym = n.sons[namePos].sym
     genProc(p.module, sym)
     if sym.loc.r == nil or sym.loc.lode == nil:
-      internalError(n.info, "expr: proc not init " & sym.name.s)
+      internalError(p.config, n.info, "expr: proc not init " & sym.name.s)
     putLocIntoDest(p, d, sym.loc)
   of nkClosure: genClosure(p, n, d)
 
@@ -2267,7 +2267,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
   of nkWhileStmt: genWhileStmt(p, n)
   of nkVarSection, nkLetSection: genVarStmt(p, n)
   of nkConstSection: discard  # consts generated lazily on use
-  of nkForStmt: internalError(n.info, "for statement not eliminated")
+  of nkForStmt: internalError(p.config, n.info, "for statement not eliminated")
   of nkCaseStmt: genCase(p, n, d)
   of nkReturnStmt: genReturnStmt(p, n)
   of nkBreakStmt: genBreakStmt(p, n)
@@ -2295,7 +2295,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
         initLocExpr(p, ex, a)
   of nkAsmStmt: genAsmStmt(p, n)
   of nkTryStmt:
-    if p.module.compileToCpp and optNoCppExceptions notin gGlobalOptions:
+    if p.module.compileToCpp and optNoCppExceptions notin p.config.globalOptions:
       genTryCpp(p, n, d)
     else:
       genTry(p, n, d)
@@ -2327,7 +2327,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
   of nkState: genState(p, n)
   of nkGotoState: genGotoState(p, n)
   of nkBreakState: genBreakState(p, n, d)
-  else: internalError(n.info, "expr(" & $n.kind & "); unknown node kind")
+  else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind")
 
 proc genNamedConstExpr(p: BProc, n: PNode): Rope =
   if n.kind == nkExprColonExpr: result = genConstExpr(p, n.sons[1])
@@ -2363,7 +2363,7 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
     if mapType(t) == ctArray: result = rope"{}"
     else: result = rope"0"
   else:
-    globalError(info, "cannot create null element for: " & $t.kind)
+    globalError(p.config, info, "cannot create null element for: " & $t.kind)
 
 proc getNullValueAux(p: BProc; t: PType; obj, cons: PNode, result: var Rope; count: var int) =
   case obj.kind
@@ -2389,7 +2389,7 @@ proc getNullValueAux(p: BProc; t: PType; obj, cons: PNode, result: var Rope; cou
     # not found, produce default value:
     result.add getDefaultValue(p, field.typ, cons.info)
   else:
-    localError(cons.info, "cannot create null element for: " & $obj)
+    localError(p.config, cons.info, "cannot create null element for: " & $obj)
 
 proc getNullValueAuxT(p: BProc; orig, t: PType; obj, cons: PNode, result: var Rope; count: var int) =
   var base = t.sons[0]
diff --git a/compiler/ccgliterals.nim b/compiler/ccgliterals.nim
index b17a5eedd..cfe71375e 100644
--- a/compiler/ccgliterals.nim
+++ b/compiler/ccgliterals.nim
@@ -15,7 +15,7 @@
 
 template detectVersion(field, corename) =
   if m.g.field == 0:
-    let core = getCompilerProc(corename)
+    let core = getCompilerProc(m.g.graph, corename)
     if core == nil or core.kind != skConst:
       m.g.field = 1
     else:
@@ -74,7 +74,7 @@ proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo): Rope =
   of 0, 1: result = genStringLiteralDataOnlyV1(m, s)
   of 2: result = genStringLiteralDataOnlyV2(m, s)
   else:
-    localError(info, "cannot determine how to produce code for string literal")
+    localError(m.config, info, "cannot determine how to produce code for string literal")
 
 proc genStringLiteralFromData(m: BModule; data: Rope; info: TLineInfo): Rope =
   result = ropecg(m, "((#NimStringDesc*) &$1)",
@@ -88,4 +88,4 @@ proc genStringLiteral(m: BModule; n: PNode): Rope =
   of 0, 1: result = genStringLiteralV1(m, n)
   of 2: result = genStringLiteralV2(m, n)
   else:
-    localError(n.info, "cannot determine how to produce code for string literal")
+    localError(m.config, n.info, "cannot determine how to produce code for string literal")
diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim
index f667be70f..4b4f9c0e6 100644
--- a/compiler/ccgmerge.nim
+++ b/compiler/ccgmerge.nim
@@ -45,28 +45,28 @@ const
   ]
   NimMergeEndMark = "/*\tNIM_merge_END:*/"
 
-proc genSectionStart*(fs: TCFileSection): Rope =
-  if compilationCachePresent:
+proc genSectionStart*(fs: TCFileSection; conf: ConfigRef): Rope =
+  if compilationCachePresent(conf):
     result = rope(tnl)
     add(result, "/*\t")
     add(result, CFileSectionNames[fs])
     add(result, ":*/")
     add(result, tnl)
 
-proc genSectionEnd*(fs: TCFileSection): Rope =
-  if compilationCachePresent:
+proc genSectionEnd*(fs: TCFileSection; conf: ConfigRef): Rope =
+  if compilationCachePresent(conf):
     result = rope(NimMergeEndMark & tnl)
 
-proc genSectionStart*(ps: TCProcSection): Rope =
-  if compilationCachePresent:
+proc genSectionStart*(ps: TCProcSection; conf: ConfigRef): Rope =
+  if compilationCachePresent(conf):
     result = rope(tnl)
     add(result, "/*\t")
     add(result, CProcSectionNames[ps])
     add(result, ":*/")
     add(result, tnl)
 
-proc genSectionEnd*(ps: TCProcSection): Rope =
-  if compilationCachePresent:
+proc genSectionEnd*(ps: TCProcSection; conf: ConfigRef): Rope =
+  if compilationCachePresent(conf):
     result = rope(NimMergeEndMark & tnl)
 
 proc writeTypeCache(a: TypeCache, s: var string) =
@@ -96,7 +96,7 @@ proc writeIntSet(a: IntSet, s: var string) =
   s.add('}')
 
 proc genMergeInfo*(m: BModule): Rope =
-  if not compilationCachePresent: return nil
+  if not compilationCachePresent(m.config): return nil
   var s = "/*\tNIM_merge_INFO:"
   s.add(tnl)
   s.add("typeCache:{")
@@ -161,7 +161,7 @@ proc readVerbatimSection(L: var TBaseLexer): Rope =
       buf = L.buf
       r.add(tnl)
     of '\0':
-      internalError("ccgmerge: expected: " & NimMergeEndMark)
+      doAssert(false, "ccgmerge: expected: " & NimMergeEndMark)
       break
     else:
       if atEndMark(buf, pos):
@@ -179,7 +179,7 @@ proc readKey(L: var TBaseLexer, result: var string) =
   while buf[pos] in IdentChars:
     result.add(buf[pos])
     inc pos
-  if buf[pos] != ':': internalError("ccgmerge: ':' expected")
+  if buf[pos] != ':': doAssert(false, "ccgmerge: ':' expected")
   L.bufpos = pos + 1 # skip ':'
 
 proc newFakeType(id: int): PType =
@@ -187,12 +187,12 @@ proc newFakeType(id: int): PType =
   result.id = id
 
 proc readTypeCache(L: var TBaseLexer, result: var TypeCache) =
-  if ^L.bufpos != '{': internalError("ccgmerge: '{' expected")
+  if ^L.bufpos != '{': doAssert(false, "ccgmerge: '{' expected")
   inc L.bufpos
   while ^L.bufpos != '}':
     skipWhite(L)
     var key = decodeStr(L.buf, L.bufpos)
-    if ^L.bufpos != ':': internalError("ccgmerge: ':' expected")
+    if ^L.bufpos != ':': doAssert(false, "ccgmerge: ':' expected")
     inc L.bufpos
     var value = decodeStr(L.buf, L.bufpos)
     # XXX implement me
@@ -201,7 +201,7 @@ proc readTypeCache(L: var TBaseLexer, result: var TypeCache) =
   inc L.bufpos
 
 proc readIntSet(L: var TBaseLexer, result: var IntSet) =
-  if ^L.bufpos != '{': internalError("ccgmerge: '{' expected")
+  if ^L.bufpos != '{': doAssert(false, "ccgmerge: '{' expected")
   inc L.bufpos
   while ^L.bufpos != '}':
     skipWhite(L)
@@ -225,7 +225,7 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) =
     of "labels":    m.labels = decodeVInt(L.buf, L.bufpos)
     of "flags":
       m.flags = cast[set[CodegenFlag]](decodeVInt(L.buf, L.bufpos) != 0)
-    else: internalError("ccgmerge: unknown key: " & k)
+    else: doAssert(false, "ccgmerge: unknown key: " & k)
 
 when not defined(nimhygiene):
   {.pragma: inject.}
@@ -275,9 +275,9 @@ proc readMergeSections(cfilename: string, m: var TMergeSections) =
         if sectionB >= 0 and sectionB <= high(TCProcSection).int:
           m.p[TCProcSection(sectionB)] = verbatim
         else:
-          internalError("ccgmerge: unknown section: " & k)
+          doAssert(false, "ccgmerge: unknown section: " & k)
     else:
-      internalError("ccgmerge: '*/' expected")
+      doAssert(false, "ccgmerge: '*/' expected")
 
 proc mergeRequired*(m: BModule): bool =
   for i in cfsHeaders..cfsProcs:
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 510dbfc18..91a3add70 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -16,7 +16,7 @@ const
     # above X strings a hash-switch for strings is generated
 
 proc registerGcRoot(p: BProc, v: PSym) =
-  if gSelectedGC in {gcMarkAndSweep, gcGenerational, gcV2, gcRefc} and
+  if p.config.selectedGC in {gcMarkAndSweep, gcGenerational, gcV2, gcRefc} and
       containsGarbageCollectedRef(v.loc.t):
     # we register a specialized marked proc here; this has the advantage
     # that it works out of the box for thread local storage then :-)
@@ -43,13 +43,13 @@ proc inExceptBlockLen(p: BProc): int =
 
 proc genVarTuple(p: BProc, n: PNode) =
   var tup, field: TLoc
-  if n.kind != nkVarTuple: internalError(n.info, "genVarTuple")
+  if n.kind != nkVarTuple: internalError(p.config, n.info, "genVarTuple")
   var L = sonsLen(n)
 
   # if we have a something that's been captured, use the lowering instead:
   for i in countup(0, L-3):
     if n[i].kind != nkSym:
-      genStmts(p, lowerTupleUnpacking(n, p.prc))
+      genStmts(p, lowerTupleUnpacking(p.module.g.graph, n, p.prc))
       return
 
   genLineDir(p, n)
@@ -70,7 +70,7 @@ proc genVarTuple(p: BProc, n: PNode) =
     if t.kind == tyTuple:
       field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
     else:
-      if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple")
+      if t.n.sons[i].kind != nkSym: internalError(p.config, n.info, "genVarTuple")
       field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n.sons[i].sym, t)]
     putLocIntoDest(p, v.loc, field)
 
@@ -125,7 +125,7 @@ proc endBlock(p: BProc, blockEnd: Rope) =
 proc endBlock(p: BProc) =
   let topBlock = p.blocks.len - 1
   var blockEnd = if p.blocks[topBlock].label != nil:
-      rfmt(nil, "} $1: ;$n", p.blocks[topBlock].label)
+      ropecg(p.module, "} $1: ;$n", p.blocks[topBlock].label)
     else:
       ~"}$n"
   let frameLen = p.blocks[topBlock].frameLen
@@ -149,7 +149,7 @@ template preserveBreakIdx(body: untyped): untyped =
   p.breakIdx = oldBreakIdx
 
 proc genState(p: BProc, n: PNode) =
-  internalAssert n.len == 1
+  internalAssert p.config, n.len == 1
   let n0 = n[0]
   if n0.kind == nkIntLit:
     let idx = n.sons[0].intVal
@@ -165,7 +165,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
 
   for i in countup(1, howManyTrys):
     let tryStmt = p.nestedTryStmts.pop
-    if not p.module.compileToCpp or optNoCppExceptions in gGlobalOptions:
+    if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions:
       # Pop safe points generated by try
       if not tryStmt.inExcept:
         linefmt(p, cpsStmts, "#popSafePoint();$n")
@@ -184,7 +184,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
   for i in countdown(howManyTrys-1, 0):
     p.nestedTryStmts.add(stack[i])
 
-  if not p.module.compileToCpp or optNoCppExceptions in gGlobalOptions:
+  if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions:
     # Pop exceptions that was handled by the
     # except-blocks we are in
     for i in countdown(howManyExcepts-1, 0):
@@ -228,7 +228,7 @@ proc genBreakState(p: BProc, n: PNode, d: var TLoc) =
 
 proc genGotoVar(p: BProc; value: PNode) =
   if value.kind notin {nkCharLit..nkUInt64Lit}:
-    localError(value.info, "'goto' target must be a literal value")
+    localError(p.config, value.info, "'goto' target must be a literal value")
   else:
     lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope])
 
@@ -362,7 +362,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
       startBlock(p)
       expr(p, it.sons[0], d)
       endBlock(p)
-    else: internalError(n.info, "genIf()")
+    else: internalError(p.config, n.info, "genIf()")
   if sonsLen(n) > 1: fixLabel(p, lend)
 
 proc genReturnStmt(p: BProc, t: PNode) =
@@ -386,7 +386,7 @@ proc genGotoForCase(p: BProc; caseStmt: PNode) =
     let it = caseStmt.sons[i]
     for j in 0 .. it.len-2:
       if it.sons[j].kind == nkRange:
-        localError(it.info, "range notation not available for computed goto")
+        localError(p.config, it.info, "range notation not available for computed goto")
         return
       let val = getOrdValue(it.sons[j])
       lineF(p, cpsStmts, "NIMSTATE_$#:$n", [val.rope])
@@ -401,19 +401,19 @@ proc genComputedGoto(p: BProc; n: PNode) =
     let it = n.sons[i]
     if it.kind == nkCaseStmt:
       if lastSon(it).kind != nkOfBranch:
-        localError(it.info,
+        localError(p.config, it.info,
             "case statement must be exhaustive for computed goto"); return
       casePos = i
       let aSize = lengthOrd(it.sons[0].typ)
       if aSize > 10_000:
-        localError(it.info,
+        localError(p.config, it.info,
             "case statement has too many cases for computed goto"); return
       arraySize = aSize.int
       if firstOrd(it.sons[0].typ) != 0:
-        localError(it.info,
+        localError(p.config, it.info,
             "case statement has to start at 0 for computed goto"); return
   if casePos < 0:
-    localError(n.info, "no case statement found for computed goto"); return
+    localError(p.config, n.info, "no case statement found for computed goto"); return
   var id = p.labels+1
   inc p.labels, arraySize+1
   let tmp = "TMP$1_" % [id.rope]
@@ -447,7 +447,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
     let it = caseStmt.sons[i]
     for j in 0 .. it.len-2:
       if it.sons[j].kind == nkRange:
-        localError(it.info, "range notation not available for computed goto")
+        localError(p.config, it.info, "range notation not available for computed goto")
         return
       let val = getOrdValue(it.sons[j])
       lineF(p, cpsStmts, "TMP$#_:$n", [intLiteral(val+id+1)])
@@ -551,7 +551,7 @@ proc genBreakStmt(p: BProc, t: PNode) =
     # an unnamed 'break' can only break a loop after 'transf' pass:
     while idx >= 0 and not p.blocks[idx].isLoop: dec idx
     if idx < 0 or not p.blocks[idx].isLoop:
-      internalError(t.info, "no loop to break")
+      internalError(p.config, t.info, "no loop to break")
   let label = assignLabel(p.blocks[idx])
   blockLeaveActions(p,
     p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts,
@@ -574,7 +574,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
     var e = rdLoc(a)
     var typ = skipTypes(t[0].typ, abstractPtrs)
     genLineDir(p, t)
-    if isImportedException(typ):
+    if isImportedException(typ, p.config):
       lineF(p, cpsStmts, "throw $1;$n", [e])
     else:
       lineCg(p, cpsStmts, "#raiseException((#Exception*)$1, $2);$n",
@@ -582,7 +582,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
   else:
     genLineDir(p, t)
     # reraise the last exception:
-    if p.module.compileToCpp and optNoCppExceptions notin gGlobalOptions:
+    if p.module.compileToCpp and optNoCppExceptions notin p.config.globalOptions:
       line(p, cpsStmts, ~"throw;$n")
     else:
       linefmt(p, cpsStmts, "#reraiseException();$n")
@@ -879,17 +879,14 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
   p.module.includeHeader("<setjmp.h>")
   genLineDir(p, t)
   var safePoint = getTempName(p.module)
-  if getCompilerProc("Exception") != nil:
-    discard cgsym(p.module, "Exception")
-  else:
-    discard cgsym(p.module, "E_Base")
+  discard cgsym(p.module, "Exception")
   linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint)
   linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint)
-  if isDefined("nimStdSetjmp"):
+  if isDefined(p.config, "nimStdSetjmp"):
     linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
-  elif isDefined("nimSigSetjmp"):
+  elif isDefined(p.config, "nimSigSetjmp"):
     linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", safePoint)
-  elif isDefined("nimRawSetjmp"):
+  elif isDefined(p.config, "nimRawSetjmp"):
     linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", safePoint)
   else:
     linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
@@ -1016,7 +1013,7 @@ proc genEmit(p: BProc, t: PNode) =
   if p.prc == nil:
     # top level emit pragma?
     let section = determineSection(t[1])
-    genCLineDir(p.module.s[section], t.info)
+    genCLineDir(p.module.s[section], t.info, p.config)
     add(p.module.s[section], s)
   else:
     genLineDir(p, t)
@@ -1142,4 +1139,4 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
 proc genStmts(p: BProc, t: PNode) =
   var a: TLoc
   expr(p, t, a)
-  internalAssert a.k in {locNone, locTemp, locLocalVar}
+  internalAssert p.config, a.k in {locNone, locTemp, locLocalVar}
diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim
index 505b69eab..da5c624b7 100644
--- a/compiler/ccgthreadvars.nim
+++ b/compiler/ccgthreadvars.nim
@@ -12,11 +12,11 @@
 
 # included from cgen.nim
 
-proc emulatedThreadVars(): bool =
-  result = {optThreads, optTlsEmulation} <= gGlobalOptions
+proc emulatedThreadVars(conf: ConfigRef): bool =
+  result = {optThreads, optTlsEmulation} <= conf.globalOptions
 
 proc accessThreadLocalVar(p: BProc, s: PSym) =
-  if emulatedThreadVars() and not p.threadVarAccessed:
+  if emulatedThreadVars(p.config) and not p.threadVarAccessed:
     p.threadVarAccessed = true
     incl p.module.flags, usesThreadVars
     addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV_;$n", [])
@@ -37,7 +37,7 @@ var
 # made to be one.
 
 proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
-  if emulatedThreadVars():
+  if emulatedThreadVars(m.config):
     # we gather all thread locals var into a struct; we need to allocate
     # storage for that somehow, can't use the thread local storage
     # allocator for it :-(
@@ -46,7 +46,7 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
       addf(nimtv, "$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.r])
   else:
     if isExtern: add(m.s[cfsVars], "extern ")
-    if optThreads in gGlobalOptions: add(m.s[cfsVars], "NIM_THREADVAR ")
+    if optThreads in m.config.globalOptions: add(m.s[cfsVars], "NIM_THREADVAR ")
     add(m.s[cfsVars], getTypeDesc(m, s.loc.t))
     addf(m.s[cfsVars], " $1;$n", [s.loc.r])
 
@@ -57,7 +57,7 @@ proc generateThreadLocalStorage(m: BModule) =
 
 proc generateThreadVarsSize(m: BModule) =
   if nimtv != nil:
-    let externc = if gCmd == cmdCompileToCpp or
+    let externc = if m.config.cmd == cmdCompileToCpp or
                        sfCompileToCpp in m.module.flags: "extern \"C\" "
                   else: ""
     addf(m.s[cfsProcs],
diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim
index 1bb2ba98d..c265064a1 100644
--- a/compiler/ccgtrav.nim
+++ b/compiler/ccgtrav.nim
@@ -29,12 +29,12 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
     for i in countup(0, sonsLen(n) - 1):
       genTraverseProc(c, accessor, n.sons[i], typ)
   of nkRecCase:
-    if (n.sons[0].kind != nkSym): internalError(n.info, "genTraverseProc")
+    if (n.sons[0].kind != nkSym): internalError(c.p.config, n.info, "genTraverseProc")
     var p = c.p
     let disc = n.sons[0].sym
     if disc.loc.r == nil: fillObjectFields(c.p.module, typ)
     if disc.loc.t == nil:
-      internalError(n.info, "genTraverseProc()")
+      internalError(c.p.config, n.info, "genTraverseProc()")
     lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r])
     for i in countup(1, sonsLen(n) - 1):
       let branch = n.sons[i]
@@ -51,9 +51,9 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
     if field.typ.kind == tyVoid: return
     if field.loc.r == nil: fillObjectFields(c.p.module, typ)
     if field.loc.t == nil:
-      internalError(n.info, "genTraverseProc()")
+      internalError(c.p.config, n.info, "genTraverseProc()")
     genTraverseProc(c, "$1.$2" % [accessor, field.loc.r], field.loc.t)
-  else: internalError(n.info, "genTraverseProc()")
+  else: internalError(c.p.config, n.info, "genTraverseProc()")
 
 proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} =
   if not m.compileToCpp:
@@ -72,12 +72,12 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
   of tyArray:
     let arraySize = lengthOrd(typ.sons[0])
     var i: TLoc
-    getTemp(p, getSysType(tyInt), i)
+    getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo(), tyInt), i)
     let oldCode = p.s(cpsStmts)
     linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
             i.r, arraySize.rope)
     let oldLen = p.s(cpsStmts).len
-    genTraverseProc(c, rfmt(nil, "$1[$2]", accessor, i.r), typ.sons[1])
+    genTraverseProc(c, ropecg(c.p.module, "$1[$2]", accessor, i.r), typ.sons[1])
     if p.s(cpsStmts).len == oldLen:
       # do not emit dummy long loops for faster debug builds:
       p.s(cpsStmts) = oldCode
@@ -92,12 +92,12 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
   of tyTuple:
     let typ = getUniqueType(typ)
     for i in countup(0, sonsLen(typ) - 1):
-      genTraverseProc(c, rfmt(nil, "$1.Field$2", accessor, i.rope), typ.sons[i])
+      genTraverseProc(c, ropecg(c.p.module, "$1.Field$2", accessor, i.rope), typ.sons[i])
   of tyRef, tyString, tySequence:
     lineCg(p, cpsStmts, c.visitorFrmt, accessor)
   of tyProc:
     if typ.callConv == ccClosure:
-      lineCg(p, cpsStmts, c.visitorFrmt, rfmt(nil, "$1.ClE_0", accessor))
+      lineCg(p, cpsStmts, c.visitorFrmt, ropecg(c.p.module, "$1.ClE_0", accessor))
   else:
     discard
 
@@ -105,7 +105,7 @@ proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
   var p = c.p
   assert typ.kind == tySequence
   var i: TLoc
-  getTemp(p, getSysType(tyInt), i)
+  getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo(), tyInt), i)
   let oldCode = p.s(cpsStmts)
   lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n",
       [i.r, accessor, rope(if c.p.module.compileToCpp: "len" else: "Sup.len")])
@@ -157,7 +157,7 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope =
   var sLoc = s.loc.r
   result = getTempName(m)
 
-  if sfThread in s.flags and emulatedThreadVars():
+  if sfThread in s.flags and emulatedThreadVars(m.config):
     accessThreadLocalVar(p, s)
     sLoc = "NimTV_->" & sLoc
 
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 56fb379bd..7b44cddad 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -122,7 +122,7 @@ proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope =
       # check consistency:
       assert($typ.loc.r == $(typ.typeName & $sig))
   result = typ.loc.r
-  if result == nil: internalError("getTypeName: " & $typ.kind)
+  if result == nil: internalError(m.config, "getTypeName: " & $typ.kind)
 
 proc mapSetType(typ: PType): TCTypeKind =
   case int(getSize(typ))
@@ -142,7 +142,7 @@ proc mapType(typ: PType): TCTypeKind =
   of tyOpenArray, tyArray, tyVarargs: result = ctArray
   of tyObject, tyTuple: result = ctStruct
   of tyUserTypeClasses:
-    internalAssert typ.isResolvedUserTypeClass
+    doAssert typ.isResolvedUserTypeClass
     return mapType(typ.lastSon)
   of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
      tyTypeDesc, tyAlias, tySink, tyInferred:
@@ -156,7 +156,7 @@ proc mapType(typ: PType): TCTypeKind =
       of 2: result = ctUInt16
       of 4: result = ctInt32
       of 8: result = ctInt64
-      else: internalError("mapType")
+      else: result = ctInt32
   of tyRange: result = mapType(typ.sons[0])
   of tyPtr, tyVar, tyLent, tyRef, tyOptAsRef:
     var base = skipTypes(typ.lastSon, typedescInst)
@@ -183,8 +183,8 @@ proc mapType(typ: PType): TCTypeKind =
     result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
   of tyStatic:
     if typ.n != nil: result = mapType(lastSon typ)
-    else: internalError("mapType")
-  else: internalError("mapType")
+    else: doAssert(false, "mapType")
+  else: doAssert(false, "mapType")
 
 proc mapReturnType(typ: PType): TCTypeKind =
   #if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
@@ -239,7 +239,7 @@ proc cacheGetType(tab: TypeCache; sig: SigHash): Rope =
   result = tab.getOrDefault(sig)
 
 proc addAbiCheck(m: BModule, t: PType, name: Rope) =
-  if isDefined("checkabi"):
+  if isDefined(m.config, "checkabi"):
     addf(m.s[cfsTypeInfo], "NIM_CHECK_SIZE($1, $2);$n", [name, rope(getSize(t))])
 
 proc ccgIntroducedPtr(s: PSym): bool =
@@ -303,7 +303,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
   of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0])
   of tyStatic:
     if typ.n != nil: result = getSimpleTypeDesc(m, lastSon typ)
-    else: internalError("tyStatic for getSimpleTypeDesc")
+    else: internalError(m.config, "tyStatic for getSimpleTypeDesc")
   of tyGenericInst, tyAlias, tySink:
     result = getSimpleTypeDesc(m, lastSon typ)
   else: result = nil
@@ -347,7 +347,7 @@ proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope =
     else:
       pushType(m, concrete)
     doAssert m.forwTypeCache[sig] == result
-  else: internalError("getTypeForward(" & $typ.kind & ')')
+  else: internalError(m.config, "getTypeForward(" & $typ.kind & ')')
 
 proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
   ## like getTypeDescAux but creates only a *weak* dependency. In other words
@@ -389,7 +389,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
   else:
     rettype = getTypeDescAux(m, t.sons[0], check)
   for i in countup(1, sonsLen(t.n) - 1):
-    if t.n.sons[i].kind != nkSym: internalError(t.n.info, "genProcParams")
+    if t.n.sons[i].kind != nkSym: internalError(m.config, t.n.info, "genProcParams")
     var param = t.n.sons[i].sym
     if isCompileTimeOnly(param.typ): continue
     if params != nil: add(params, ~", ")
@@ -442,7 +442,7 @@ proc mangleRecFieldName(m: BModule; field: PSym, rectype: PType): Rope =
     result = field.loc.r
   else:
     result = rope(mangleField(m, field.name))
-  if result == nil: internalError(field.info, "mangleRecFieldName")
+  if result == nil: internalError(m.config, field.info, "mangleRecFieldName")
 
 proc genRecordFieldsAux(m: BModule, n: PNode,
                         accessExpr: Rope, rectype: PType,
@@ -453,7 +453,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
     for i in countup(0, sonsLen(n) - 1):
       add(result, genRecordFieldsAux(m, n.sons[i], accessExpr, rectype, check))
   of nkRecCase:
-    if n.sons[0].kind != nkSym: internalError(n.info, "genRecordFieldsAux")
+    if n.sons[0].kind != nkSym: internalError(m.config, n.info, "genRecordFieldsAux")
     add(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check))
     let uname = rope(mangle(n.sons[0].sym.name.s) & 'U')
     let ae = if accessExpr != nil: "$1.$2" % [accessExpr, uname]
@@ -481,7 +481,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
               addf(unionBody, "#pragma pack(pop)$n", [])
         else:
           add(unionBody, genRecordFieldsAux(m, k, ae, rectype, check))
-      else: internalError("genRecordFieldsAux(record case branch)")
+      else: internalError(m.config, "genRecordFieldsAux(record case branch)")
     if unionBody != nil:
       addf(result, "union{$n$1} $2;$n", [unionBody, uname])
   of nkSym:
@@ -509,7 +509,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
         # don't use fieldType here because we need the
         # tyGenericInst for C++ template support
         addf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
-  else: internalError(n.info, "genRecordFieldsAux()")
+  else: internalError(m.config, n.info, "genRecordFieldsAux()")
 
 proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope =
   result = genRecordFieldsAux(m, typ.n, nil, typ, check)
@@ -556,7 +556,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
           # proper request to generate popCurrentExceptionEx not possible for 2 reasons:
           # generated function will be below declared Exception type and circular dependency
           # between Exception and popCurrentExceptionEx function
-          result = genProcHeader(m, magicsys.getCompilerProc("popCurrentExceptionEx")) & ";" & rnl & result
+          result = genProcHeader(m, magicsys.getCompilerProc(m.g.graph, "popCurrentExceptionEx")) & ";" & rnl & result
       hasField = true
     else:
       appcg(m, result, " {$n  $1 Sup;$n",
@@ -606,7 +606,7 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
   # Make sure the index refers to one of the generic params of the type.
   # XXX: we should catch this earlier and report it as a semantic error.
   if idx >= typ.len:
-    internalError "invalid apostrophe type parameter index"
+    doAssert false, "invalid apostrophe type parameter index"
 
   result = typ.sons[idx]
   for i in 1..stars:
@@ -619,7 +619,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
   var t = origTyp.skipTypes(irrelevantForBackend)
   if containsOrIncl(check, t.id):
     if not (isImportedCppType(origTyp) or isImportedCppType(t)):
-      internalError("cannot generate C type for: " & typeToString(origTyp))
+      internalError(m.config, "cannot generate C type for: " & typeToString(origTyp))
     # XXX: this BUG is hard to fix -> we need to introduce helper structs,
     # but determining when this needs to be done is hard. We should split
     # C type generation into an analysis and a code generation phase somehow.
@@ -697,7 +697,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
           of 2: addf(m.s[cfsTypes], "typedef NU16 $1;$n", [result])
           of 4: addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result])
           of 8: addf(m.s[cfsTypes], "typedef NI64 $1;$n", [result])
-          else: internalError(t.sym.info, "getTypeDescAux: enum")
+          else: internalError(m.config, t.sym.info, "getTypeDescAux: enum")
         when false:
           let owner = hashOwner(t.sym)
           if not gDebugInfo.hasEnum(t.sym.name.s, t.sym.info.line, owner):
@@ -808,7 +808,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
             if typeInSlot == nil or typeInSlot.kind == tyVoid:
               result.add(~"void")
             elif typeInSlot.kind == tyStatic:
-              internalAssert typeInSlot.n != nil
+              internalAssert m.config, typeInSlot.n != nil
               result.add typeInSlot.n.renderTree
             else:
               result.add getTypeDescAux(m, typeInSlot, check)
@@ -875,7 +875,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
      tyUserTypeClass, tyUserTypeClassInst, tyInferred:
     result = getTypeDescAux(m, lastSon(t), check)
   else:
-    internalError("getTypeDescAux(" & $t.kind & ')')
+    internalError(m.config, "getTypeDescAux(" & $t.kind & ')')
     result = nil
   # fixes bug #145:
   excl(check, t.id)
@@ -915,7 +915,7 @@ template cgDeclFrmt*(s: PSym): string = s.constraint.strVal
 proc genProcHeader(m: BModule, prc: PSym): Rope =
   var
     rettype, params: Rope
-  genCLineDir(result, prc.info)
+  genCLineDir(result, prc.info, m.config)
   # using static is needed for inline procs
   if lfExportLib in prc.loc.flags:
     if isHeaderFile in m.flags:
@@ -968,7 +968,7 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType;
   if flags != 0:
     addf(m.s[cfsTypeInit3], "$1.flags = $2;$n", [name, rope(flags)])
   discard cgsym(m, "TNimType")
-  if isDefined("nimTypeNames"):
+  if isDefined(m.config, "nimTypeNames"):
     var typename = typeToString(if origType.typeInst != nil: origType.typeInst
                                 else: origType, preferName)
     if typename == "ref object" and origType.skipTypes(skipPtrs).sym != nil:
@@ -1000,7 +1000,7 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope =
   while lookupInRecord(objtype.n, d.name) == nil:
     objtype = objtype.sons[0]
   if objtype.sym == nil:
-    internalError(d.info, "anonymous obj with discriminator")
+    internalError(m.config, d.info, "anonymous obj with discriminator")
   result = "NimDT_$1_$2" % [rope($hashType(objtype)), rope(d.name.s.mangle)]
 
 proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope =
@@ -1034,7 +1034,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
     assert L > 0
     if field.loc.r == nil: fillObjectFields(m, typ)
     if field.loc.t == nil:
-      internalError(n.info, "genObjectFields")
+      internalError(m.config, n.info, "genObjectFields")
     addf(m.s[cfsTypeInit3], "$1.kind = 3;$n" &
         "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
         "$1.name = $5;$n" & "$1.sons = &$6[0];$n" &
@@ -1050,7 +1050,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
       case b.kind
       of nkOfBranch:
         if sonsLen(b) < 2:
-          internalError(b.info, "genObjectFields; nkOfBranch broken")
+          internalError(m.config, b.info, "genObjectFields; nkOfBranch broken")
         for j in countup(0, sonsLen(b) - 2):
           if b.sons[j].kind == nkRange:
             var x = int(getOrdValue(b.sons[j].sons[0]))
@@ -1064,23 +1064,23 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
       of nkElse:
         addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
              [tmp, rope(L), tmp2])
-      else: internalError(n.info, "genObjectFields(nkRecCase)")
+      else: internalError(m.config, n.info, "genObjectFields(nkRecCase)")
   of nkSym:
     var field = n.sym
     if field.bitsize == 0:
       if field.loc.r == nil: fillObjectFields(m, typ)
       if field.loc.t == nil:
-        internalError(n.info, "genObjectFields")
+        internalError(m.config, n.info, "genObjectFields")
       addf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
           "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
           "$1.name = $5;$n", [expr, getTypeDesc(m, origType),
           field.loc.r, genTypeInfo(m, field.typ, info), makeCString(field.name.s)])
-  else: internalError(n.info, "genObjectFields")
+  else: internalError(m.config, n.info, "genObjectFields")
 
 proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo) =
   if typ.kind == tyObject:
     if incompleteType(typ):
-      localError(info, "request for RTTI generation for incomplete object: " &
+      localError(m.config, info, "request for RTTI generation for incomplete object: " &
                         typeToString(typ))
     genTypeInfoAux(m, typ, origType, name, info)
   else:
@@ -1171,12 +1171,12 @@ proc genSetInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
 proc genArrayInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
   genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1], info), info)
 
-proc fakeClosureType(owner: PSym): PType =
+proc fakeClosureType(m: BModule; owner: PSym): PType =
   # we generate the same RTTI as for a tuple[pointer, ref tuple[]]
   result = newType(tyTuple, owner)
   result.rawAddSon(newType(tyPointer, owner))
   var r = newType(tyRef, owner)
-  let obj = createObj(owner, owner.info, final=false)
+  let obj = createObj(m.g.graph, owner, owner.info, final=false)
   r.rawAddSon(obj)
   result.rawAddSon(r)
 
@@ -1227,19 +1227,19 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
     genTypeInfoAuxBase(m, t, t, result, rope"0", info)
   of tyStatic:
     if t.n != nil: result = genTypeInfo(m, lastSon t, info)
-    else: internalError("genTypeInfo(" & $t.kind & ')')
+    else: internalError(m.config, "genTypeInfo(" & $t.kind & ')')
   of tyUserTypeClasses:
-    internalAssert t.isResolvedUserTypeClass
+    internalAssert m.config, t.isResolvedUserTypeClass
     return genTypeInfo(m, t.lastSon, info)
   of tyProc:
     if t.callConv != ccClosure:
       genTypeInfoAuxBase(m, t, t, result, rope"0", info)
     else:
-      let x = fakeClosureType(t.owner)
+      let x = fakeClosureType(m, t.owner)
       genTupleInfo(m, x, x, result, info)
   of tySequence, tyRef, tyOptAsRef:
     genTypeInfoAux(m, t, t, result, info)
-    if gSelectedGC >= gcMarkAndSweep:
+    if m.config.selectedGC >= gcMarkAndSweep:
       let markerProc = genTraverseProc(m, origType, sig)
       addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
   of tyPtr, tyRange: genTypeInfoAux(m, t, t, result, info)
@@ -1253,7 +1253,7 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
     # BUGFIX: use consistently RTTI without proper field names; otherwise
     # results are not deterministic!
     genTupleInfo(m, t, origType, result, info)
-  else: internalError("genTypeInfo(" & $t.kind & ')')
+  else: internalError(m.config, "genTypeInfo(" & $t.kind & ')')
   if t.deepCopy != nil:
     genDeepCopyProc(m, t.deepCopy, result)
   elif origType.deepCopy != nil:
diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim
index 48648bdde..a6080a808 100644
--- a/compiler/ccgutils.nim
+++ b/compiler/ccgutils.nim
@@ -53,7 +53,7 @@ proc hashString*(s: string): BiggestInt =
     result = a
 
 var
-  gTypeTable: array[TTypeKind, TIdTable]
+  gTypeTable: array[TTypeKind, TIdTable]  # XXX globals here
   gCanonicalTypes: array[TTypeKind, PType]
 
 proc initTypeTables() =
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 693930fbc..133e86cea 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -19,6 +19,7 @@ import
 import strutils except `%` # collides with ropes.`%`
 
 from modulegraphs import ModuleGraph
+from configuration import warnGcMem, errXMustBeCompileTime, hintDependency, errGenerated
 import dynlib
 
 when not declared(dynlib.libCandidates):
@@ -92,6 +93,7 @@ proc useHeader(m: BModule, sym: PSym) =
 proc cgsym(m: BModule, name: string): Rope
 
 proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
+  assert m != nil
   var i = 0
   var length = len(frmt)
   result = nil
@@ -115,15 +117,15 @@ proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
           if i >= length or not (frmt[i] in {'0'..'9'}): break
         num = j
         if j > high(args) + 1:
-          internalError("ropes: invalid format string $" & $j)
+          internalError(m.config, "ropes: invalid format string $" & $j)
         add(result, args[j-1])
       of 'n':
-        if optLineDir notin gOptions: add(result, rnl)
+        if optLineDir notin m.config.options: add(result, rnl)
         inc(i)
       of 'N':
         add(result, rnl)
         inc(i)
-      else: internalError("ropes: invalid format string $" & frmt[i])
+      else: internalError(m.config, "ropes: invalid format string $" & frmt[i])
     elif frmt[i] == '#' and frmt[i+1] in IdentStartChars:
       inc(i)
       var j = i
@@ -145,15 +147,10 @@ proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
     if i - 1 >= start:
       add(result, substr(frmt, start, i - 1))
 
-template rfmt(m: BModule, fmt: string, args: varargs[Rope]): untyped =
-  ropecg(m, fmt, args)
-
-var indent = "\t".rope
-
 proc indentLine(p: BProc, r: Rope): Rope =
   result = r
   for i in countup(0, p.blocks.len-1):
-    prepend(result, indent)
+    prepend(result, "\t".rope)
 
 proc appcg(m: BModule, c: var Rope, frmt: FormatStr,
            args: varargs[Rope]) =
@@ -189,14 +186,14 @@ proc safeLineNm(info: TLineInfo): int =
   result = toLinenumber(info)
   if result < 0: result = 0 # negative numbers are not allowed in #line
 
-proc genCLineDir(r: var Rope, filename: string, line: int) =
+proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) =
   assert line >= 0
-  if optLineDir in gOptions:
+  if optLineDir in conf.options:
     addf(r, "$N#line $2 $1$N",
         [rope(makeSingleLineCString(filename)), rope(line)])
 
-proc genCLineDir(r: var Rope, info: TLineInfo) =
-  genCLineDir(r, info.toFullPath, info.safeLineNm)
+proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) =
+  genCLineDir(r, info.toFullPath, info.safeLineNm, conf)
 
 proc freshLineInfo(p: BProc; info: TLineInfo): bool =
   if p.lastLineInfo.line != info.line or
@@ -213,9 +210,9 @@ proc genLineDir(p: BProc, t: PNode) =
     tt = tt.sons[1]
   let line = tt.info.safeLineNm
 
-  if optEmbedOrigSrc in gGlobalOptions:
-    add(p.s(cpsStmts), ~"//" & tt.info.sourceLine & rnl)
-  genCLineDir(p.s(cpsStmts), tt.info.toFullPath, line)
+  if optEmbedOrigSrc in p.config.globalOptions:
+    add(p.s(cpsStmts), ~"//" & sourceLine(p.config, tt.info) & rnl)
+  genCLineDir(p.s(cpsStmts), tt.info.toFullPath, line, p.config)
   if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and
       (p.prc == nil or sfPure notin p.prc.flags):
     if freshLineInfo(p, tt.info):
@@ -226,17 +223,17 @@ proc genLineDir(p: BProc, t: PNode) =
       (p.prc == nil or sfPure notin p.prc.flags) and tt.info.fileIndex != InvalidFileIDX:
     if freshLineInfo(p, tt.info):
       linefmt(p, cpsStmts, "nimln_($1, $2);$n",
-              line.rope, tt.info.quotedFilename)
+              line.rope, quotedFilename(p.config, tt.info))
 
 proc postStmtActions(p: BProc) {.inline.} =
   add(p.s(cpsStmts), p.module.injectStmt)
 
 proc accessThreadLocalVar(p: BProc, s: PSym)
-proc emulatedThreadVars(): bool {.inline.}
+proc emulatedThreadVars(conf: ConfigRef): bool {.inline.}
 proc genProc(m: BModule, prc: PSym)
 
 template compileToCpp(m: BModule): untyped =
-  gCmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags
+  m.config.cmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags
 
 proc getTempName(m: BModule): Rope =
   result = m.tmpBase & rope(m.labels)
@@ -265,7 +262,7 @@ proc rdCharLoc(a: TLoc): Rope =
 
 proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
                    takeAddr: bool) =
-  if p.module.compileToCpp and t.isException and not isDefined("noCppExceptions"):
+  if p.module.compileToCpp and t.isException and not isDefined(p.config, "noCppExceptions"):
     # init vtable in Exception object for polymorphic exceptions
     includeHeader(p.module, "<new>")
     linefmt(p, section, "new ($1) $2;$n", rdLoc(a), getTypeDesc(p.module, t))
@@ -373,7 +370,7 @@ proc getIntTemp(p: BProc, result: var TLoc) =
   linefmt(p, cpsLocals, "NI $1;$n", result.r)
   result.k = locTemp
   result.storage = OnStack
-  result.lode = lodeTyp getSysType(tyInt)
+  result.lode = lodeTyp getSysType(p.module.g.graph, unknownLineInfo(), tyInt)
   result.flags = {}
 
 proc initGCFrame(p: BProc): Rope =
@@ -417,7 +414,7 @@ proc assignLocalVar(p: BProc, n: PNode) =
   #assert(s.loc.k == locNone) # not yet assigned
   # this need not be fulfilled for inline procs; they are regenerated
   # for each module that uses them!
-  let nl = if optLineDir in gOptions: "" else: tnl
+  let nl = if optLineDir in p.config.options: "" else: tnl
   let decl = localVarDecl(p, n) & ";" & nl
   line(p, cpsLocals, decl)
   localDebugInfo(p, n.sym)
@@ -511,24 +508,24 @@ proc initFrame(p: BProc, procname, filename: Rope): Rope =
   discard cgsym(p.module, "nimFrame")
   if p.maxFrameLen > 0:
     discard cgsym(p.module, "VarSlot")
-    result = rfmt(nil, "\tnimfrs_($1, $2, $3, $4);$n",
+    result = ropecg(p.module, "\tnimfrs_($1, $2, $3, $4);$n",
                   procname, filename, p.maxFrameLen.rope,
                   p.blocks[0].frameLen.rope)
   else:
-    result = rfmt(nil, "\tnimfr_($1, $2);$n", procname, filename)
+    result = ropecg(p.module, "\tnimfr_($1, $2);$n", procname, filename)
 
 proc initFrameNoDebug(p: BProc; frame, procname, filename: Rope; line: int): Rope =
   discard cgsym(p.module, "nimFrame")
   addf(p.blocks[0].sections[cpsLocals], "TFrame $1;$n", [frame])
-  result = rfmt(nil, "\t$1.procname = $2; $1.filename = $3; " &
+  result = ropecg(p.module, "\t$1.procname = $2; $1.filename = $3; " &
                       " $1.line = $4; $1.len = -1; nimFrame(&$1);$n",
                       frame, procname, filename, rope(line))
 
 proc deinitFrameNoDebug(p: BProc; frame: Rope): Rope =
-  result = rfmt(p.module, "\t#popFrameOfAddr(&$1);$n", frame)
+  result = ropecg(p.module, "\t#popFrameOfAddr(&$1);$n", frame)
 
 proc deinitFrame(p: BProc): Rope =
-  result = rfmt(p.module, "\t#popFrame();$n")
+  result = ropecg(p.module, "\t#popFrame();$n")
 
 include ccgexprs
 
@@ -551,7 +548,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
     if lib.path.kind in {nkStrLit..nkTripleStrLit}:
       var s: TStringSeq = @[]
       libCandidates(lib.path.strVal, s)
-      rawMessage(hintDependency, lib.path.strVal)
+      rawMessage(m.config, hintDependency, lib.path.strVal)
       var loadlib: Rope = nil
       for i in countup(0, high(s)):
         inc(m.labels)
@@ -575,7 +572,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
            "if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n",
            [tmp, rdLoc(dest)])
 
-  if lib.name == nil: internalError("loadDynamicLib")
+  if lib.name == nil: internalError(m.config, "loadDynamicLib")
 
 proc mangleDynLibProc(sym: PSym): Rope =
   if sfCompilerProc in sym.flags:
@@ -606,14 +603,14 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
         [tmp, getTypeDesc(m, sym.typ), params, makeCString($extname)]
     var last = lastSon(n)
     if last.kind == nkHiddenStdConv: last = last.sons[1]
-    internalAssert(last.kind == nkStrLit)
+    internalAssert(m.config, last.kind == nkStrLit)
     let idx = last.strVal
     if idx.len == 0:
       add(m.initProc.s(cpsStmts), load)
     elif idx.len == 1 and idx[0] in {'0'..'9'}:
       add(m.extensionLoaders[idx[0]], load)
     else:
-      internalError(sym.info, "wrong index: " & idx)
+      internalError(m.config, sym.info, "wrong index: " & idx)
   else:
     appcg(m, m.s[cfsDynLibInit],
         "\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
@@ -639,18 +636,18 @@ proc symInDynamicLibPartial(m: BModule, sym: PSym) =
   sym.typ.sym = nil           # generate a new name
 
 proc cgsym(m: BModule, name: string): Rope =
-  let sym = magicsys.getCompilerProc(name)
+  let sym = magicsys.getCompilerProc(m.g.graph, name)
   if sym != nil:
     case sym.kind
     of skProc, skFunc, skMethod, skConverter, skIterator: genProc(m, sym)
     of skVar, skResult, skLet: genVarPrototype(m, newSymNode sym)
     of skType: discard getTypeDesc(m, sym.typ)
-    else: internalError("cgsym: " & name & ": " & $sym.kind)
+    else: internalError(m.config, "cgsym: " & name & ": " & $sym.kind)
   else:
     # we used to exclude the system module from this check, but for DLL
     # generation support this sloppyness leads to hard to detect bugs, so
     # we're picky here for the system module too:
-    rawMessage(errSystemNeeds, name)
+    rawMessage(m.config, errGenerated, "system module needs: " & name)
   result = sym.loc.r
 
 proc generateHeaders(m: BModule) =
@@ -687,7 +684,7 @@ proc closureSetup(p: BProc, prc: PSym) =
   # prc.ast[paramsPos].last contains the type we're after:
   var ls = lastSon(prc.ast[paramsPos])
   if ls.kind != nkSym:
-    internalError(prc.info, "closure generation failed")
+    internalError(p.config, prc.info, "closure generation failed")
   var env = ls.sym
   #echo "created environment: ", env.id, " for ", prc.name.s
   assignLocalVar(p, ls)
@@ -727,7 +724,7 @@ proc genProcAux(m: BModule, prc: PSym) =
   assert(prc.ast != nil)
   if sfPure notin prc.flags and prc.typ.sons[0] != nil:
     if resultPos >= prc.ast.len:
-      internalError(prc.info, "proc has no result symbol")
+      internalError(m.config, prc.info, "proc has no result symbol")
     let resNode = prc.ast.sons[resultPos]
     let res = resNode.sym # get result symbol
     if not isInvalidReturnType(prc.typ.sons[0]):
@@ -742,7 +739,7 @@ proc genProcAux(m: BModule, prc: PSym) =
         assignLocalVar(p, resNode)
         assert(res.loc.r != nil)
         initLocalVar(p, res, immediateAsgn=false)
-      returnStmt = rfmt(nil, "\treturn $1;$n", rdLoc(res.loc))
+      returnStmt = ropecg(p.module, "\treturn $1;$n", rdLoc(res.loc))
     else:
       fillResult(resNode)
       assignParam(p, res)
@@ -764,15 +761,15 @@ proc genProcAux(m: BModule, prc: PSym) =
   if sfPure in prc.flags:
     if hasDeclspec in extccomp.CC[extccomp.cCompiler].props:
       header = "__declspec(naked) " & header
-    generatedProc = rfmt(nil, "$N$1 {$n$2$3$4}$N$N",
+    generatedProc = ropecg(p.module, "$N$1 {$n$2$3$4}$N$N",
                          header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts))
   else:
-    generatedProc = rfmt(nil, "$N$1 {$N", header)
+    generatedProc = ropecg(p.module, "$N$1 {$N", header)
     add(generatedProc, initGCFrame(p))
     if optStackTrace in prc.options:
       add(generatedProc, p.s(cpsLocals))
       var procname = makeCString(prc.name.s)
-      add(generatedProc, initFrame(p, procname, prc.info.quotedFilename))
+      add(generatedProc, initFrame(p, procname, quotedFilename(p.config, prc.info)))
     else:
       add(generatedProc, p.s(cpsLocals))
     if optProfiler in prc.options:
@@ -791,10 +788,10 @@ proc genProcAux(m: BModule, prc: PSym) =
 proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} =
   result = (sfCompileToCpp in m.module.flags and
            sfCompileToCpp notin sym.getModule().flags and
-           gCmd != cmdCompileToCpp) or (
+           m.config.cmd != cmdCompileToCpp) or (
            sym.flags * {sfImportc, sfInfixCall, sfCompilerProc} == {sfImportc} and
            sym.magic == mNone and
-           gCmd == cmdCompileToCpp)
+           m.config.cmd == cmdCompileToCpp)
 
 proc genProcPrototype(m: BModule, sym: PSym) =
   useHeader(m, sym)
@@ -802,7 +799,7 @@ proc genProcPrototype(m: BModule, sym: PSym) =
   if lfDynamicLib in sym.loc.flags:
     if getModule(sym).id != m.module.id and
         not containsOrIncl(m.declaredThings, sym.id):
-      add(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n",
+      add(m.s[cfsVars], ropecg(m, "extern $1 $2;$n",
                         getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)))
   elif not containsOrIncl(m.declaredProtos, sym.id):
     var header = genProcHeader(m, sym)
@@ -814,7 +811,7 @@ proc genProcPrototype(m: BModule, sym: PSym) =
       header.add(" __attribute__((naked))")
     if sfNoReturn in sym.flags and hasAttribute in CC[cCompiler].props:
       header.add(" __attribute__((noreturn))")
-    add(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
+    add(m.s[cfsProcHeaders], ropecg(m, "$1;$n", header))
 
 proc genProcNoForward(m: BModule, prc: PSym) =
   if lfImportCompilerProc in prc.loc.flags:
@@ -920,14 +917,14 @@ proc genVarPrototype(m: BModule, n: PNode) =
       if sfVolatile in sym.flags: add(m.s[cfsVars], " volatile")
       addf(m.s[cfsVars], " $1;$n", [sym.loc.r])
 
-proc addIntTypes(result: var Rope) {.inline.} =
+proc addIntTypes(result: var Rope; conf: ConfigRef) {.inline.} =
   addf(result, "#define NIM_NEW_MANGLING_RULES" & tnl &
                "#define NIM_INTBITS $1" & tnl, [
     platform.CPU[targetCPU].intSize.rope])
-  if useNimNamespace : result.add("#define USE_NIM_NAMESPACE" & tnl)
+  if optUseNimNamespace in conf.globalOptions: result.add("#define USE_NIM_NAMESPACE" & tnl)
 
-proc getCopyright(cfile: Cfile): Rope =
-  if optCompileOnly in gGlobalOptions:
+proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope =
+  if optCompileOnly in conf.globalOptions:
     result = ("/* Generated by Nim Compiler v$1 */$N" &
         "/*   (c) " & copyrightYear & " Andreas Rumpf */$N" &
         "/* The generated code is subject to the original license. */$N") %
@@ -942,11 +939,11 @@ proc getCopyright(cfile: Cfile): Rope =
         rope(platform.OS[targetOS].name),
         rope(platform.CPU[targetCPU].name),
         rope(extccomp.CC[extccomp.cCompiler].name),
-        rope(getCompileCFileCmd(cfile))]
+        rope(getCompileCFileCmd(conf, cfile))]
 
-proc getFileHeader(cfile: Cfile): Rope =
-  result = getCopyright(cfile)
-  addIntTypes(result)
+proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope =
+  result = getCopyright(conf, cfile)
+  addIntTypes(result, conf)
 
 proc genFilenames(m: BModule): Rope =
   discard cgsym(m, "dbgRegisterFilename")
@@ -1051,8 +1048,8 @@ proc genMainProc(m: BModule) =
 
   var nimMain, otherMain: FormatStr
   if platform.targetOS == osWindows and
-      gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}:
-    if optGenGuiApp in gGlobalOptions:
+      m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}:
+    if optGenGuiApp in m.config.globalOptions:
       nimMain = WinNimMain
       otherMain = WinCMain
     else:
@@ -1062,7 +1059,7 @@ proc genMainProc(m: BModule) =
   elif platform.targetOS == osGenode:
     nimMain = GenodeNimMain
     otherMain = ComponentConstruct
-  elif optGenDynLib in gGlobalOptions:
+  elif optGenDynLib in m.config.globalOptions:
     nimMain = PosixNimDllMain
     otherMain = PosixCDllMain
   elif platform.targetOS == osStandalone:
@@ -1072,16 +1069,16 @@ proc genMainProc(m: BModule) =
     nimMain = PosixNimMain
     otherMain = PosixCMain
   if m.g.breakpoints != nil: discard cgsym(m, "dbgRegisterBreakpoint")
-  if optEndb in gOptions:
+  if optEndb in m.config.options:
     m.g.breakpoints.add(m.genFilenames)
 
   let initStackBottomCall =
-    if platform.targetOS == osStandalone or gSelectedGC == gcNone: "".rope
+    if platform.targetOS == osStandalone or m.config.selectedGC == gcNone: "".rope
     else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N")
   inc(m.labels)
   appcg(m, m.s[cfsProcs], PreMainBody, [
     m.g.mainDatInit, m.g.breakpoints, m.g.otherModsInit,
-     if emulatedThreadVars() and platform.targetOS != osStandalone:
+     if emulatedThreadVars(m.config) and platform.targetOS != osStandalone:
        ropecg(m, "\t#initThreadVarsEmulation();$N")
      else:
        "".rope,
@@ -1089,12 +1086,12 @@ proc genMainProc(m: BModule) =
 
   appcg(m, m.s[cfsProcs], nimMain,
         [m.g.mainModInit, initStackBottomCall, rope(m.labels)])
-  if optNoMain notin gGlobalOptions:
-    if useNimNamespace:
+  if optNoMain notin m.config.globalOptions:
+    if optUseNimNamespace in m.config.globalOptions:
       m.s[cfsProcs].add closeNamespaceNim() & "using namespace Nim;" & tnl
 
     appcg(m, m.s[cfsProcs], otherMain, [])
-    if useNimNamespace: m.s[cfsProcs].add openNamespaceNim()
+    if optUseNimNamespace in m.config.globalOptions: m.s[cfsProcs].add openNamespaceNim()
 
 proc getSomeInitName(m: PSym, suffix: string): Rope =
   assert m.kind == skModule
@@ -1140,11 +1137,11 @@ proc genInitCode(m: BModule) =
 
   add(prc, initGCFrame(m.initProc))
 
-  add(prc, genSectionStart(cpsLocals))
+  add(prc, genSectionStart(cpsLocals, m.config))
   add(prc, m.preInitProc.s(cpsLocals))
   add(prc, m.initProc.s(cpsLocals))
   add(prc, m.postInitProc.s(cpsLocals))
-  add(prc, genSectionEnd(cpsLocals))
+  add(prc, genSectionEnd(cpsLocals, m.config))
 
   if optStackTrace in m.initProc.options and frameDeclared notin m.flags:
     # BUT: the generated init code might depend on a current frame, so
@@ -1152,21 +1149,21 @@ proc genInitCode(m: BModule) =
     incl m.flags, frameDeclared
     if preventStackTrace notin m.flags:
       var procname = makeCString(m.module.name.s)
-      add(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
+      add(prc, initFrame(m.initProc, procname, quotedFilename(m.config, m.module.info)))
     else:
       add(prc, ~"\tTFrame FR_; FR_.len = 0;$N")
 
-  add(prc, genSectionStart(cpsInit))
+  add(prc, genSectionStart(cpsInit, m.config))
   add(prc, m.preInitProc.s(cpsInit))
   add(prc, m.initProc.s(cpsInit))
   add(prc, m.postInitProc.s(cpsInit))
-  add(prc, genSectionEnd(cpsInit))
+  add(prc, genSectionEnd(cpsInit, m.config))
 
-  add(prc, genSectionStart(cpsStmts))
+  add(prc, genSectionStart(cpsStmts, m.config))
   add(prc, m.preInitProc.s(cpsStmts))
   add(prc, m.initProc.s(cpsStmts))
   add(prc, m.postInitProc.s(cpsStmts))
-  add(prc, genSectionEnd(cpsStmts))
+  add(prc, genSectionEnd(cpsStmts, m.config))
   if optStackTrace in m.initProc.options and preventStackTrace notin m.flags:
     add(prc, deinitFrame(m.initProc))
   add(prc, deinitGCFrame(m.initProc))
@@ -1176,9 +1173,9 @@ proc genInitCode(m: BModule) =
            [getDatInitName(m.module)])
 
   for i in cfsTypeInit1..cfsDynLibInit:
-    add(prc, genSectionStart(i))
+    add(prc, genSectionStart(i, m.config))
     add(prc, m.s[i])
-    add(prc, genSectionEnd(i))
+    add(prc, genSectionEnd(i, m.config))
 
   addf(prc, "}$N$N", [])
   # we cannot simply add the init proc to ``m.s[cfsProcs]`` anymore because
@@ -1193,18 +1190,19 @@ proc genInitCode(m: BModule) =
       add(m.s[cfsInitProc], ex)
 
 proc genModule(m: BModule, cfile: Cfile): Rope =
-  result = getFileHeader(cfile)
+  result = getFileHeader(m.config, cfile)
   result.add(genMergeInfo(m))
 
   generateThreadLocalStorage(m)
   generateHeaders(m)
   for i in countup(cfsHeaders, cfsProcs):
-    add(result, genSectionStart(i))
+    add(result, genSectionStart(i, m.config))
     add(result, m.s[i])
-    add(result, genSectionEnd(i))
-    if useNimNamespace and i == cfsHeaders: result.add openNamespaceNim()
+    add(result, genSectionEnd(i, m.config))
+    if optUseNimNamespace in m.config.globalOptions and i == cfsHeaders:
+      result.add openNamespaceNim()
   add(result, m.s[cfsInitProc])
-  if useNimNamespace: result.add closeNamespaceNim()
+  if optUseNimNamespace in m.config.globalOptions: result.add closeNamespaceNim()
 
 proc newPreInitProc(m: BModule): BProc =
   result = newProc(nil, m)
@@ -1217,10 +1215,12 @@ proc newPostInitProc(m: BModule): BProc =
   result.labels = 200_000
 
 proc initProcOptions(m: BModule): TOptions =
-  if sfSystemModule in m.module.flags: gOptions-{optStackTrace} else: gOptions
+  let opts = m.config.options
+  if sfSystemModule in m.module.flags: opts-{optStackTrace} else: opts
 
 proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule =
   new(result)
+  result.g = g
   result.tmpBase = rope("TM" & $hashOwner(module) & "_")
   result.headerFiles = @[]
   result.declaredThings = initIntSet()
@@ -1241,14 +1241,13 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule =
   result.forwardedProcs = @[]
   result.typeNodesName = getTempName(result)
   result.nimTypesName = getTempName(result)
-  result.g = g
   # no line tracing for the init sections of the system module so that we
   # don't generate a TFrame which can confuse the stack botton initialization:
   if sfSystemModule in module.flags:
     incl result.flags, preventStackTrace
     excl(result.preInitProc.options, optStackTrace)
     excl(result.postInitProc.options, optStackTrace)
-  let ndiName = if optCDebug in gGlobalOptions: changeFileExt(completeCFilePath(filename), "ndi")
+  let ndiName = if optCDebug in g.config.globalOptions: changeFileExt(completeCFilePath(g.config, filename), "ndi")
                 else: ""
   open(result.ndi, ndiName)
 
@@ -1309,18 +1308,19 @@ proc newModule(g: BModuleList; module: PSym): BModule =
   growCache g.modules, module.position
   g.modules[module.position] = result
 
-template injectG(config) {.dirty.} =
+template injectG() {.dirty.} =
   if graph.backend == nil:
-    graph.backend = newModuleList(config)
+    graph.backend = newModuleList(graph)
   let g = BModuleList(graph.backend)
 
 proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
-  injectG(graph.config)
+  injectG()
   result = newModule(g, module)
-  if optGenIndex in gGlobalOptions and g.generatedHeader == nil:
-    let f = if graph.config.headerFile.len > 0: graph.config.headerFile else: gProjectFull
+  if optGenIndex in graph.config.globalOptions and g.generatedHeader == nil:
+    let f = if graph.config.headerFile.len > 0: graph.config.headerFile
+            else: graph.config.projectFull
     g.generatedHeader = rawNewModule(g, module,
-      changeFileExt(completeCFilePath(f), hExt))
+      changeFileExt(completeCFilePath(graph.config, f), hExt))
     incl g.generatedHeader.flags, isHeaderFile
 
 proc writeHeader(m: BModule) =
@@ -1331,43 +1331,44 @@ proc writeHeader(m: BModule) =
 
   var guard = "__$1__" % [m.filename.splitFile.name.rope]
   result.addf("#ifndef $1$n#define $1$n", [guard])
-  addIntTypes(result)
+  addIntTypes(result, m.config)
   generateHeaders(m)
 
   generateThreadLocalStorage(m)
   for i in countup(cfsHeaders, cfsProcs):
-    add(result, genSectionStart(i))
+    add(result, genSectionStart(i, m.config))
     add(result, m.s[i])
-    add(result, genSectionEnd(i))
-    if useNimNamespace and i == cfsHeaders: result.add openNamespaceNim()
+    add(result, genSectionEnd(i, m.config))
+    if optUseNimNamespace in m.config.globalOptions and i == cfsHeaders: result.add openNamespaceNim()
   add(result, m.s[cfsInitProc])
 
-  if optGenDynLib in gGlobalOptions:
+  if optGenDynLib in m.config.globalOptions:
     result.add("N_LIB_IMPORT ")
   result.addf("N_CDECL(void, NimMain)(void);$n", [])
-  if useNimNamespace: result.add closeNamespaceNim()
+  if optUseNimNamespace in m.config.globalOptions: result.add closeNamespaceNim()
   result.addf("#endif /* $1 */$n", [guard])
   writeRope(result, m.filename)
 
 proc getCFile(m: BModule): string =
   let ext =
       if m.compileToCpp: ".cpp"
-      elif gCmd == cmdCompileToOC or sfCompileToObjC in m.module.flags: ".m"
+      elif m.config.cmd == cmdCompileToOC or sfCompileToObjC in m.module.flags: ".m"
       else: ".c"
-  result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), ext)
+  result = changeFileExt(completeCFilePath(m.config, withPackageName(m.config, m.cfilename)), ext)
 
 proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext =
-  injectG(graph.config)
+  injectG()
   var m = newModule(g, module)
   readMergeInfo(getCFile(m), m)
   result = m
 
 proc myProcess(b: PPassContext, n: PNode): PNode =
   result = n
-  if b == nil or passes.skipCodegen(n): return
+  if b == nil: return
   var m = BModule(b)
+  if passes.skipCodegen(m.config, n): return
   m.initProc.options = initProcOptions(m)
-  softRnl = if optLineDir in gOptions: noRnl else: rnl
+  softRnl = if optLineDir in m.config.options: noRnl else: rnl
   genStmts(m.initProc, n)
 
 proc finishModule(m: BModule) =
@@ -1377,18 +1378,18 @@ proc finishModule(m: BModule) =
     # a ``for`` loop here
     var prc = m.forwardedProcs[i]
     if sfForward in prc.flags:
-      internalError(prc.info, "still forwarded: " & prc.name.s)
+      internalError(m.config, prc.info, "still forwarded: " & prc.name.s)
     genProcNoForward(m, prc)
     inc(i)
   assert(m.g.forwardedProcsCounter >= i)
   dec(m.g.forwardedProcsCounter, i)
   setLen(m.forwardedProcs, 0)
 
-proc shouldRecompile(code: Rope, cfile: Cfile): bool =
+proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool =
   result = true
-  if optForceFullMake notin gGlobalOptions:
+  if optForceFullMake notin m.config.globalOptions:
     if not equalsFile(code, cfile.cname):
-      if isDefined("nimdiff"):
+      if isDefined(m.config, "nimdiff"):
         if fileExists(cfile.cname):
           copyFile(cfile.cname, cfile.cname & ".backup")
           echo "diff ", cfile.cname, ".backup ", cfile.cname
@@ -1411,7 +1412,7 @@ proc writeModule(m: BModule, pending: bool) =
   # generate code for the init statements of the module:
   let cfile = getCFile(m)
 
-  if m.rd == nil or optForceFullMake in gGlobalOptions:
+  if m.rd == nil or optForceFullMake in m.config.globalOptions:
     genInitCode(m)
     finishTypeDescriptions(m)
     if sfMainModule in m.module.flags:
@@ -1419,35 +1420,35 @@ proc writeModule(m: BModule, pending: bool) =
       add(m.s[cfsProcHeaders], m.g.mainModProcs)
       generateThreadVarsSize(m)
 
-    var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {})
+    var cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
     var code = genModule(m, cf)
     when hasTinyCBackend:
-      if gCmd == cmdRun:
+      if conf.cmd == cmdRun:
         tccgen.compileCCode($code)
         return
 
-    if not shouldRecompile(code, cf): cf.flags = {CfileFlag.Cached}
-    addFileToCompile(cf)
+    if not shouldRecompile(m, code, cf): cf.flags = {CfileFlag.Cached}
+    addFileToCompile(m.config, cf)
   elif pending and mergeRequired(m) and sfMainModule notin m.module.flags:
-    let cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {})
+    let cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
     mergeFiles(cfile, m)
     genInitCode(m)
     finishTypeDescriptions(m)
     var code = genModule(m, cf)
     writeRope(code, cfile)
-    addFileToCompile(cf)
+    addFileToCompile(m.config, cf)
   else:
     # Consider: first compilation compiles ``system.nim`` and produces
     # ``system.c`` but then compilation fails due to an error. This means
     # that ``system.o`` is missing, so we need to call the C compiler for it:
-    var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {})
+    var cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
     if not existsFile(cf.obj): cf.flags = {CfileFlag.Cached}
-    addFileToCompile(cf)
+    addFileToCompile(m.config, cf)
   close(m.ndi)
 
 proc updateCachedModule(m: BModule) =
   let cfile = getCFile(m)
-  var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {})
+  var cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
 
   if mergeRequired(m) and sfMainModule notin m.module.flags:
     mergeFiles(cfile, m)
@@ -1458,12 +1459,13 @@ proc updateCachedModule(m: BModule) =
     writeRope(code, cfile)
   else:
     cf.flags = {CfileFlag.Cached}
-  addFileToCompile(cf)
+  addFileToCompile(m.config, cf)
 
 proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
   result = n
-  if b == nil or passes.skipCodegen(n): return
+  if b == nil: return
   var m = BModule(b)
+  if passes.skipCodegen(m.config, n): return
   # if the module is cached, we don't regenerate the main proc
   # nor the dispatchers? But if the dispatchers changed?
   # XXX emit the dispatchers into its own .c file?
@@ -1497,7 +1499,7 @@ proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
       m.updateCachedModule
     else:
       m.writeModule(pending=true)
-  writeMapping(g.mapping)
+  writeMapping(config, g.mapping)
   if g.generatedHeader != nil: writeHeader(g.generatedHeader)
 
 const cgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index f8167acdc..ce3fc2f90 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -14,6 +14,7 @@ import
   tables, ndi
 
 from msgs import TLineInfo
+from modulegraphs import ModuleGraph
 
 type
   TLabel* = Rope              # for the C generator a label is just a rope
@@ -116,6 +117,7 @@ type
     breakpoints*: Rope # later the breakpoints are inserted into the main proc
     typeInfoMarker*: TypeCache
     config*: ConfigRef
+    graph*: ModuleGraph
     strVersion*, seqVersion*: int # version of the string/seq implementation to use
 
   TCGen = object of TPassContext # represents a C source file
@@ -148,6 +150,9 @@ type
     g*: BModuleList
     ndi*: NdiFile
 
+template config*(m: BModule): ConfigRef = m.g.config
+template config*(p: BProc): ConfigRef = p.module.g.config
+
 proc includeHeader*(this: BModule; header: string) =
   if not this.headerFiles.contains header:
     this.headerFiles.add header
@@ -165,14 +170,15 @@ proc newProc*(prc: PSym, module: BModule): BProc =
   result.prc = prc
   result.module = module
   if prc != nil: result.options = prc.options
-  else: result.options = gOptions
+  else: result.options = module.config.options
   newSeq(result.blocks, 1)
   result.nestedTryStmts = @[]
   result.finallySafePoints = @[]
   result.sigConflicts = initCountTable[string]()
 
-proc newModuleList*(config: ConfigRef): BModuleList =
-  BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope](), config: config)
+proc newModuleList*(g: ModuleGraph): BModuleList =
+  BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope](), config: g.config,
+    graph: g)
 
 iterator cgenModules*(g: BModuleList): BModule =
   for i in 0..high(g.modules):
diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim
index 0513e88f4..1d72952e2 100644
--- a/compiler/cgmeth.nim
+++ b/compiler/cgmeth.nim
@@ -11,9 +11,9 @@
 
 import
   intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys,
-  sempass2, strutils, modulegraphs
+  sempass2, strutils, modulegraphs, configuration
 
-proc genConv(n: PNode, d: PType, downcast: bool): PNode =
+proc genConv(n: PNode, d: PType, downcast: bool; conf: ConfigRef): PNode =
   var dest = skipTypes(d, abstractPtrs)
   var source = skipTypes(n.typ, abstractPtrs)
   if (source.kind == tyObject) and (dest.kind == tyObject):
@@ -24,12 +24,12 @@ proc genConv(n: PNode, d: PType, downcast: bool): PNode =
     elif diff < 0:
       result = newNodeIT(nkObjUpConv, n.info, d)
       addSon(result, n)
-      if downcast: internalError(n.info, "cgmeth.genConv: no upcast allowed")
+      if downcast: internalError(conf, n.info, "cgmeth.genConv: no upcast allowed")
     elif diff > 0:
       result = newNodeIT(nkObjDownConv, n.info, d)
       addSon(result, n)
       if not downcast:
-        internalError(n.info, "cgmeth.genConv: no downcast allowed")
+        internalError(conf, n.info, "cgmeth.genConv: no downcast allowed")
     else:
       result = n
   else:
@@ -42,7 +42,7 @@ proc getDispatcher*(s: PSym): PSym =
     let disp = dispn.sym
     if sfDispatcher in disp.flags: result = disp
 
-proc methodCall*(n: PNode): PNode =
+proc methodCall*(n: PNode; conf: ConfigRef): PNode =
   result = n
   # replace ordinary method by dispatcher method:
   let disp = getDispatcher(result.sons[0].sym)
@@ -50,9 +50,9 @@ proc methodCall*(n: PNode): PNode =
     result.sons[0].sym = disp
     # change the arguments to up/downcasts to fit the dispatcher's parameters:
     for i in countup(1, sonsLen(result)-1):
-      result.sons[i] = genConv(result.sons[i], disp.typ.sons[i], true)
+      result.sons[i] = genConv(result.sons[i], disp.typ.sons[i], true, conf)
   else:
-    localError(n.info, "'" & $result.sons[0] & "' lacks a dispatcher")
+    localError(conf, n.info, "'" & $result.sons[0] & "' lacks a dispatcher")
 
 type
   MethodResult = enum No, Invalid, Yes
@@ -130,7 +130,7 @@ proc createDispatcher(s: PSym): PSym =
   attachDispatcher(disp, newSymNode(disp))
   return disp
 
-proc fixupDispatcher(meth, disp: PSym) =
+proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) =
   # We may have constructed the dispatcher from a method prototype
   # and need to augment the incomplete dispatcher with information
   # from later definitions, particularly the resultPos slot. Also,
@@ -149,7 +149,7 @@ proc fixupDispatcher(meth, disp: PSym) =
       disp.typ.lockLevel = meth.typ.lockLevel
     elif meth.typ.lockLevel != UnspecifiedLockLevel and
          meth.typ.lockLevel != disp.typ.lockLevel:
-      message(meth.info, warnLockLevel,
+      message(conf, meth.info, warnLockLevel,
         "method has lock level $1, but another method has $2" %
         [$meth.typ.lockLevel, $disp.typ.lockLevel])
       # XXX The following code silences a duplicate warning in
@@ -166,13 +166,13 @@ proc methodDef*(g: ModuleGraph; s: PSym, fromCache: bool) =
     of Yes:
       add(g.methods[i].methods, s)
       attachDispatcher(s, lastSon(disp.ast))
-      fixupDispatcher(s, disp)
+      fixupDispatcher(s, disp, g.config)
       #echo "fixup ", disp.name.s, " ", disp.id
-      when useEffectSystem: checkMethodEffects(disp, s)
+      when useEffectSystem: checkMethodEffects(g, disp, s)
       if {sfBase, sfFromGeneric} * s.flags == {sfBase} and
            g.methods[i].methods[0] != s:
         # already exists due to forwarding definition?
-        localError(s.info, "method is not a base")
+        localError(g.config, s.info, "method is not a base")
       return
     of No: discard
     of Invalid:
@@ -183,10 +183,10 @@ proc methodDef*(g: ModuleGraph; s: PSym, fromCache: bool) =
   #if fromCache:
   #  internalError(s.info, "no method dispatcher found")
   if witness != nil:
-    localError(s.info, "invalid declaration order; cannot attach '" & s.name.s &
+    localError(g.config, s.info, "invalid declaration order; cannot attach '" & s.name.s &
                        "' to method defined here: " & $witness.info)
   elif sfBase notin s.flags:
-    message(s.info, warnUseBase)
+    message(g.config, s.info, warnUseBase)
 
 proc relevantCol(methods: TSymSeq, col: int): bool =
   # returns true iff the position is relevant
@@ -225,32 +225,33 @@ proc sortBucket(a: var TSymSeq, relevantCols: IntSet) =
       a[j] = v
     if h == 1: break
 
-proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
+proc genDispatcher(g: ModuleGraph; methods: TSymSeq, relevantCols: IntSet): PSym =
   var base = lastSon(methods[0].ast).sym
   result = base
   var paramLen = sonsLen(base.typ)
   var nilchecks = newNodeI(nkStmtList, base.info)
   var disp = newNodeI(nkIfStmt, base.info)
-  var ands = getSysSym("and")
-  var iss = getSysSym("of")
+  var ands = getSysSym(g, unknownLineInfo(), "and")
+  var iss = getSysSym(g, unknownLineInfo(), "of")
+  let boolType = getSysType(g, unknownLineInfo(), tyBool)
   for col in countup(1, paramLen - 1):
     if contains(relevantCols, col):
       let param = base.typ.n.sons[col].sym
       if param.typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}:
         addSon(nilchecks, newTree(nkCall,
-            newSymNode(getCompilerProc"chckNilDisp"), newSymNode(param)))
+            newSymNode(getCompilerProc(g, "chckNilDisp")), newSymNode(param)))
   for meth in countup(0, high(methods)):
     var curr = methods[meth]      # generate condition:
     var cond: PNode = nil
     for col in countup(1, paramLen - 1):
       if contains(relevantCols, col):
-        var isn = newNodeIT(nkCall, base.info, getSysType(tyBool))
+        var isn = newNodeIT(nkCall, base.info, boolType)
         addSon(isn, newSymNode(iss))
         let param = base.typ.n.sons[col].sym
         addSon(isn, newSymNode(param))
         addSon(isn, newNodeIT(nkType, base.info, curr.typ.sons[col]))
         if cond != nil:
-          var a = newNodeIT(nkCall, base.info, getSysType(tyBool))
+          var a = newNodeIT(nkCall, base.info, boolType)
           addSon(a, newSymNode(ands))
           addSon(a, cond)
           addSon(a, isn)
@@ -262,7 +263,7 @@ proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
     addSon(call, newSymNode(curr))
     for col in countup(1, paramLen - 1):
       addSon(call, genConv(newSymNode(base.typ.n.sons[col].sym),
-                           curr.typ.sons[col], false))
+                           curr.typ.sons[col], false, g.config))
     var ret: PNode
     if retTyp != nil:
       var a = newNodeI(nkFastAsgn, base.info)
@@ -290,4 +291,4 @@ proc generateMethodDispatchers*(g: ModuleGraph): PNode =
       if relevantCol(g.methods[bucket].methods, col): incl(relevantCols, col)
     sortBucket(g.methods[bucket].methods, relevantCols)
     addSon(result,
-           newSymNode(genDispatcher(g.methods[bucket].methods, relevantCols)))
+           newSymNode(genDispatcher(g, g.methods[bucket].methods, relevantCols)))
diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim
index 193a812e1..86b63e34b 100644
--- a/compiler/closureiters.nim
+++ b/compiler/closureiters.nim
@@ -132,10 +132,11 @@
 
 import
   intsets, strutils, options, ast, astalgo, trees, treetab, msgs, idents,
-  renderer, types, magicsys, rodread, lowerings, lambdalifting
+  renderer, types, magicsys, rodread, lowerings, lambdalifting, modulegraphs
 
 type
   Ctx = object
+    g: ModuleGraph
     fn: PSym
     stateVarSym: PSym # :state variable. nil if env already introduced by lambdalifting
     tmpResultSym: PSym # Used when we return, but finally has to interfere
@@ -156,7 +157,8 @@ type
 
 proc newStateAccess(ctx: var Ctx): PNode =
   if ctx.stateVarSym.isNil:
-    result = rawIndirectAccess(newSymNode(getEnvParam(ctx.fn)), getStateField(ctx.fn), ctx.fn.info)
+    result = rawIndirectAccess(newSymNode(getEnvParam(ctx.fn)),
+        getStateField(ctx.g, ctx.fn), ctx.fn.info)
   else:
     result = newSymNode(ctx.stateVarSym)
 
@@ -168,7 +170,7 @@ proc newStateAssgn(ctx: var Ctx, toValue: PNode): PNode =
 proc newStateAssgn(ctx: var Ctx, stateNo: int = -2): PNode =
   # Creates state assignment:
   #   :state = stateNo
-  ctx.newStateAssgn(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
+  ctx.newStateAssgn(newIntTypeNode(nkIntLit, stateNo, ctx.g.getSysType(TLineInfo(), tyInt)))
 
 proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym =
   result = newSym(skVar, getIdent(name), ctx.fn, ctx.fn.info)
@@ -197,14 +199,14 @@ proc newTmpResultAccess(ctx: var Ctx): PNode =
     ctx.tmpResultSym = ctx.newEnvVar(":tmpResult", ctx.fn.typ[0])
   ctx.newEnvVarAccess(ctx.tmpResultSym)
 
-proc newUnrollFinallyAccess(ctx: var Ctx): PNode =
+proc newUnrollFinallyAccess(ctx: var Ctx, info: TLineInfo): PNode =
   if ctx.unrollFinallySym.isNil:
-    ctx.unrollFinallySym = ctx.newEnvVar(":unrollFinally", getSysType(tyBool))
+    ctx.unrollFinallySym = ctx.newEnvVar(":unrollFinally", ctx.g.getSysType(info, tyBool))
   ctx.newEnvVarAccess(ctx.unrollFinallySym)
 
 proc newCurExcAccess(ctx: var Ctx): PNode =
   if ctx.curExcSym.isNil:
-    ctx.curExcSym = ctx.newEnvVar(":curExc", callCodegenProc("getCurrentException", emptyNode).typ)
+    ctx.curExcSym = ctx.newEnvVar(":curExc", ctx.g.callCodegenProc("getCurrentException", emptyNode).typ)
   ctx.newEnvVarAccess(ctx.curExcSym)
 
 proc newState(ctx: var Ctx, n, gotoOut: PNode): int =
@@ -213,7 +215,7 @@ proc newState(ctx: var Ctx, n, gotoOut: PNode): int =
   # Returns index of the newly created state
 
   result = ctx.states.len
-  let resLit = newIntLit(result)
+  let resLit = ctx.g.newIntLit(n.info, result)
   let s = newNodeI(nkState, n.info)
   s.add(resLit)
   s.add(n)
@@ -222,7 +224,7 @@ proc newState(ctx: var Ctx, n, gotoOut: PNode): int =
 
   if not gotoOut.isNil:
     assert(gotoOut.len == 0)
-    gotoOut.add(newIntLit(result))
+    gotoOut.add(ctx.g.newIntLit(gotoOut.info, result))
 
 proc toStmtList(n: PNode): PNode =
   result = n
@@ -303,13 +305,14 @@ proc newNullifyCurExc(ctx: var Ctx, info: TLineInfo): PNode =
   nilnode.typ = curExc.typ
   result = newTree(nkAsgn, curExc, nilnode)
 
-proc newOr(a, b: PNode): PNode {.inline.} =
-  result = newTree(nkCall, newSymNode(getSysMagic("or", mOr)), a, b)
-  result.typ = getSysType(tyBool)
+proc newOr(g: ModuleGraph, a, b: PNode): PNode {.inline.} =
+  result = newTree(nkCall, newSymNode(g.getSysMagic(a.info, "or", mOr)), a, b)
+  result.typ = g.getSysType(a.info, tyBool)
   result.info = a.info
 
 proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} =
   var ifStmt = newNodeI(nkIfStmt, n.info)
+  let g = ctx.g
   for c in n:
     if c.kind == nkExceptBranch:
       var ifBranch: PNode
@@ -319,16 +322,16 @@ proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} =
         for i in 0 .. c.len - 2:
           assert(c[i].kind == nkType)
           let nextCond = newTree(nkCall,
-            newSymNode(getSysMagic("of", mOf)),
-            callCodegenProc("getCurrentException", emptyNode),
+            newSymNode(g.getSysMagic(c.info, "of", mOf)),
+            g.callCodegenProc("getCurrentException", emptyNode),
             c[i])
-          nextCond.typ = getSysType(tyBool)
+          nextCond.typ = ctx.g.getSysType(c.info, tyBool)
           nextCond.info = c.info
 
           if cond.isNil:
             cond = nextCond
           else:
-            cond = newOr(cond, nextCond)
+            cond = g.newOr(cond, nextCond)
 
         ifBranch = newNodeI(nkElifBranch, c.info)
         ifBranch.add(cond)
@@ -354,16 +357,16 @@ proc addElseToExcept(ctx: var Ctx, n: PNode) =
 
     block: # :unrollFinally = true
       branchBody.add(newTree(nkAsgn,
-        ctx.newUnrollFinallyAccess(),
-        newIntTypeNode(nkIntLit, 1, getSysType(tyBool))))
+        ctx.newUnrollFinallyAccess(n.info),
+        newIntTypeNode(nkIntLit, 1, ctx.g.getSysType(n.info, tyBool))))
 
     block: # :curExc = getCurrentException()
       branchBody.add(newTree(nkAsgn,
         ctx.newCurExcAccess(),
-        callCodegenProc("getCurrentException", emptyNode)))
+        ctx.g.callCodegenProc("getCurrentException", emptyNode)))
 
     block: # goto nearestFinally
-      branchBody.add(newTree(nkGotoState, newIntLit(ctx.nearestFinally)))
+      branchBody.add(newTree(nkGotoState, ctx.g.newIntLit(n.info, ctx.nearestFinally)))
 
     let elseBranch = newTree(nkElse, branchBody)
     n[1].add(elseBranch)
@@ -423,9 +426,9 @@ proc convertExprBodyToAsgn(ctx: Ctx, exprBody: PNode, res: PSym): PNode =
   result = newNodeI(nkStmtList, exprBody.info)
   ctx.addExprAssgn(result, exprBody, res)
 
-proc newNotCall(e: PNode): PNode =
-  result = newTree(nkCall, newSymNode(getSysMagic("not", mNot), e.info), e)
-  result.typ = getSysType(tyBool)
+proc newNotCall(g: ModuleGraph; e: PNode): PNode =
+  result = newTree(nkCall, newSymNode(g.getSysMagic(e.info, "not", mNot), e.info), e)
+  result.typ = g.getSysType(e.info, tyBool)
 
 proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
   result = n
@@ -458,7 +461,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
       needsSplit = true
 
       result = newNodeI(nkStmtListExpr, n.info)
-      if n.typ.isNil: internalError("lowerStmtListExprs: constr typ.isNil")
+      if n.typ.isNil: internalError(ctx.g.config, "lowerStmtListExprs: constr typ.isNil")
       result.typ = n.typ
 
       for i in 0 ..< n.len:
@@ -530,7 +533,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
             newBranch[1] = branchBody
 
         else:
-          internalError("lowerStmtListExpr(nkIf): " & $branch.kind)
+          internalError(ctx.g.config, "lowerStmtListExpr(nkIf): " & $branch.kind)
 
       if isExpr: result.add(ctx.newEnvVarAccess(tmp))
 
@@ -560,7 +563,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
           of nkFinally:
             discard
           else:
-            internalError("lowerStmtListExpr(nkTryStmt): " & $branch.kind)
+            internalError(ctx.g.config, "lowerStmtListExpr(nkTryStmt): " & $branch.kind)
         result.add(n)
         result.add(ctx.newEnvVarAccess(tmp))
 
@@ -592,7 +595,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
           of nkElse:
             branch[0] = ctx.convertExprBodyToAsgn(branch[0], tmp)
           else:
-            internalError("lowerStmtListExpr(nkCaseStmt): " & $branch.kind)
+            internalError(ctx.g.config, "lowerStmtListExpr(nkCaseStmt): " & $branch.kind)
         result.add(n)
         result.add(ctx.newEnvVarAccess(tmp))
 
@@ -623,7 +626,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
 
         var check = ctx.newEnvVarAccess(tmp)
         if n[0].sym.magic == mOr:
-          check = newNotCall(check)
+          check = ctx.g.newNotCall(check)
 
         cond = n[2]
         let ifBody = newNodeI(nkStmtList, cond.info)
@@ -727,11 +730,11 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
       if condNeedsSplit:
         let (st, ex) = exprToStmtList(n[0])
         let brk = newTree(nkBreakStmt, emptyNode)
-        let branch = newTree(nkElifBranch, newNotCall(ex), brk)
+        let branch = newTree(nkElifBranch, ctx.g.newNotCall(ex), brk)
         let check = newTree(nkIfStmt, branch)
         let newBody = newTree(nkStmtList, st, check, n[1])
 
-        n[0] = newSymNode(getSysSym("true"))
+        n[0] = newSymNode(ctx.g.getSysSym(n[0].info, "true"))
         n[1] = newBody
   else:
     for i in 0 ..< n.len:
@@ -747,8 +750,8 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
   let curExc = ctx.newCurExcAccess()
   let nilnode = newNode(nkNilLit)
   nilnode.typ = curExc.typ
-  let cmp = newTree(nkCall, newSymNode(getSysMagic("==", mEqRef), info), curExc, nilnode)
-  cmp.typ = getSysType(tyBool)
+  let cmp = newTree(nkCall, newSymNode(ctx.g.getSysMagic(info, "==", mEqRef), info), curExc, nilnode)
+  cmp.typ = ctx.g.getSysType(info, tyBool)
 
   let asgn = newTree(nkFastAsgn,
     newSymNode(getClosureIterResult(ctx.fn), info),
@@ -758,12 +761,12 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
   let branch = newTree(nkElifBranch, cmp, retStmt)
 
   # The C++ backend requires `getCurrentException` here.
-  let raiseStmt = newTree(nkRaiseStmt, callCodegenProc("getCurrentException", emptyNode))
+  let raiseStmt = newTree(nkRaiseStmt, ctx.g.callCodegenProc("getCurrentException", emptyNode))
   raiseStmt.info = info
   let elseBranch = newTree(nkElse, raiseStmt)
 
   let ifBody = newTree(nkIfStmt, branch, elseBranch)
-  let elifBranch = newTree(nkElifBranch, ctx.newUnrollFinallyAccess(), ifBody)
+  let elifBranch = newTree(nkElifBranch, ctx.newUnrollFinallyAccess(info), ifBody)
   elifBranch.info = info
   result = newTree(nkIfStmt, elifBranch)
 
@@ -779,8 +782,8 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode =
 
     block: # :unrollFinally = true
       let asgn = newNodeI(nkAsgn, n.info)
-      asgn.add(ctx.newUnrollFinallyAccess())
-      asgn.add(newIntTypeNode(nkIntLit, 1, getSysType(tyBool)))
+      asgn.add(ctx.newUnrollFinallyAccess(n.info))
+      asgn.add(newIntTypeNode(nkIntLit, 1, ctx.g.getSysType(n.info, tyBool)))
       result.add(asgn)
 
     if n[0].kind != nkEmpty:
@@ -791,8 +794,7 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode =
 
     result.add(ctx.newNullifyCurExc(n.info))
 
-    let goto = newNodeI(nkGotoState, n.info)
-    goto.add(newIntLit(ctx.nearestFinally))
+    let goto = newTree(nkGotoState, ctx.g.newIntLit(n.info, ctx.nearestFinally))
     result.add(goto)
 
   of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit,
@@ -831,7 +833,7 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
           n.sons.setLen(i + 1)
           discard ctx.newState(s, go)
           if ctx.transformClosureIteratorBody(s, gotoOut) != s:
-            internalError("transformClosureIteratorBody != s")
+            internalError(ctx.g.config, "transformClosureIteratorBody != s")
           break
 
     of nkYieldStmt:
@@ -940,24 +942,24 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
         ctx.curExcHandlingState = exceptIdx
 
         if ctx.transformReturnsInTry(tryBody) != tryBody:
-          internalError("transformReturnsInTry != tryBody")
+          internalError(ctx.g.config, "transformReturnsInTry != tryBody")
         if ctx.transformClosureIteratorBody(tryBody, outToFinally) != tryBody:
-          internalError("transformClosureIteratorBody != tryBody")
+          internalError(ctx.g.config, "transformClosureIteratorBody != tryBody")
 
         ctx.curExcHandlingState = finallyIdx
         ctx.addElseToExcept(exceptBody)
         if ctx.transformReturnsInTry(exceptBody) != exceptBody:
-          internalError("transformReturnsInTry != exceptBody")
+          internalError(ctx.g.config, "transformReturnsInTry != exceptBody")
         if ctx.transformClosureIteratorBody(exceptBody, outToFinally) != exceptBody:
-          internalError("transformClosureIteratorBody != exceptBody")
+          internalError(ctx.g.config, "transformClosureIteratorBody != exceptBody")
 
         ctx.curExcHandlingState = oldExcHandlingState
         ctx.nearestFinally = oldNearestFinally
         if ctx.transformClosureIteratorBody(finallyBody, gotoOut) != finallyBody:
-          internalError("transformClosureIteratorBody != finallyBody")
+          internalError(ctx.g.config, "transformClosureIteratorBody != finallyBody")
 
     of nkGotoState, nkForStmt:
-      internalError("closure iter " & $n.kind)
+      internalError(ctx.g.config, "closure iter " & $n.kind)
 
     else:
       for i in 0 ..< n.len:
@@ -1074,11 +1076,11 @@ proc skipThroughEmptyStates(ctx: var Ctx, n: PNode): PNode =
     for i in 0 ..< n.len:
       n[i] = ctx.skipThroughEmptyStates(n[i])
 
-proc newArrayType(n: int, t: PType, owner: PSym): PType =
+proc newArrayType(g: ModuleGraph; n: int, t: PType, owner: PSym): PType =
   result = newType(tyArray, owner)
 
   let rng = newType(tyRange, owner)
-  rng.n = newTree(nkRange, newIntLit(0), newIntLit(n))
+  rng.n = newTree(nkRange, g.newIntLit(owner.info, 0), g.newIntLit(owner.info, n))
   rng.rawAddSon(t)
 
   result.rawAddSon(rng)
@@ -1086,14 +1088,14 @@ proc newArrayType(n: int, t: PType, owner: PSym): PType =
 
 proc createExceptionTable(ctx: var Ctx): PNode {.inline.} =
   result = newNodeI(nkBracket, ctx.fn.info)
-  result.typ = newArrayType(ctx.exceptionTable.len, getSysType(tyInt16), ctx.fn)
+  result.typ = ctx.g.newArrayType(ctx.exceptionTable.len, ctx.g.getSysType(ctx.fn.info, tyInt16), ctx.fn)
 
   for i in ctx.exceptionTable:
     let elem = newIntNode(nkIntLit, i)
-    elem.typ = getSysType(tyInt16)
+    elem.typ = ctx.g.getSysType(ctx.fn.info, tyInt16)
     result.add(elem)
 
-proc newCatchBody(ctx: var Ctx): PNode {.inline.} =
+proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
   # Generates the code:
   # :state = exceptionTable[:state]
   # if :state == 0: raise
@@ -1102,7 +1104,10 @@ proc newCatchBody(ctx: var Ctx): PNode {.inline.} =
   #   :state = -:state
   # :curExc = getCurrentException()
 
-  result = newNodeI(nkStmtList, ctx.fn.info)
+  result = newNodeI(nkStmtList, info)
+
+  let intTyp = ctx.g.getSysType(info, tyInt)
+  let boolTyp = ctx.g.getSysType(info, tyBool)
 
   # :state = exceptionTable[:state]
   block:
@@ -1111,7 +1116,7 @@ proc newCatchBody(ctx: var Ctx): PNode {.inline.} =
     let getNextState = newTree(nkBracketExpr,
       ctx.createExceptionTable(),
       ctx.newStateAccess())
-    getNextState.typ = getSysType(tyInt)
+    getNextState.typ = intTyp
 
     # :state = exceptionTable[:state]
     result.add(ctx.newStateAssgn(getNextState))
@@ -1119,10 +1124,10 @@ proc newCatchBody(ctx: var Ctx): PNode {.inline.} =
   # if :state == 0: raise
   block:
     let cond = newTree(nkCall,
-      getSysMagic("==", mEqI).newSymNode(),
+      ctx.g.getSysMagic(info, "==", mEqI).newSymNode(),
       ctx.newStateAccess(),
-      newIntTypeNode(nkIntLit, 0, getSysType(tyInt)))
-    cond.typ = getSysType(tyBool)
+      newIntTypeNode(nkIntLit, 0, intTyp))
+    cond.typ = boolTyp
 
     let raiseStmt = newTree(nkRaiseStmt, emptyNode)
     let ifBranch = newTree(nkElifBranch, cond, raiseStmt)
@@ -1132,26 +1137,26 @@ proc newCatchBody(ctx: var Ctx): PNode {.inline.} =
   # :unrollFinally = :state > 0
   block:
     let cond = newTree(nkCall,
-      getSysMagic("<", mLtI).newSymNode,
-      newIntTypeNode(nkIntLit, 0, getSysType(tyInt)),
+      ctx.g.getSysMagic(info, "<", mLtI).newSymNode,
+      newIntTypeNode(nkIntLit, 0, intTyp),
       ctx.newStateAccess())
-    cond.typ = getSysType(tyBool)
+    cond.typ = boolTyp
 
-    let asgn = newTree(nkAsgn, ctx.newUnrollFinallyAccess(), cond)
+    let asgn = newTree(nkAsgn, ctx.newUnrollFinallyAccess(info), cond)
     result.add(asgn)
 
   # if :state < 0: :state = -:state
   block:
     let cond = newTree(nkCall,
-      getSysMagic("<", mLtI).newSymNode,
+      ctx.g.getSysMagic(info, "<", mLtI).newSymNode,
       ctx.newStateAccess(),
-      newIntTypeNode(nkIntLit, 0, getSysType(tyInt)))
-    cond.typ = getSysType(tyBool)
+      newIntTypeNode(nkIntLit, 0, intTyp))
+    cond.typ = boolTyp
 
     let negateState = newTree(nkCall,
-      getSysMagic("-", mUnaryMinusI).newSymNode,
+      ctx.g.getSysMagic(info, "-", mUnaryMinusI).newSymNode,
       ctx.newStateAccess())
-    negateState.typ = getSysType(tyInt)
+    negateState.typ = intTyp
 
     let ifBranch = newTree(nkElifBranch, cond, ctx.newStateAssgn(negateState))
     let ifStmt = newTree(nkIfStmt, ifBranch)
@@ -1161,15 +1166,15 @@ proc newCatchBody(ctx: var Ctx): PNode {.inline.} =
   block:
     result.add(newTree(nkAsgn,
       ctx.newCurExcAccess(),
-      callCodegenProc("getCurrentException", emptyNode)))
+      ctx.g.callCodegenProc("getCurrentException", emptyNode)))
 
 proc wrapIntoTryExcept(ctx: var Ctx, n: PNode): PNode {.inline.} =
   let setupExc = newTree(nkCall,
-    newSymNode(getCompilerProc("closureIterSetupExc")),
+    newSymNode(ctx.g.getCompilerProc("closureIterSetupExc")),
     ctx.newCurExcAccess())
 
   let tryBody = newTree(nkStmtList, setupExc, n)
-  let exceptBranch = newTree(nkExceptBranch, ctx.newCatchBody())
+  let exceptBranch = newTree(nkExceptBranch, ctx.newCatchBody(ctx.fn.info))
 
   result = newTree(nkTryStmt, tryBody, exceptBranch)
 
@@ -1179,7 +1184,7 @@ proc wrapIntoStateLoop(ctx: var Ctx, n: PNode): PNode =
   #     gotoState :state
   #     body # Might get wrapped in try-except
   let loopBody = newNodeI(nkStmtList, n.info)
-  result = newTree(nkWhileStmt, newSymNode(getSysSym("true")), loopBody)
+  result = newTree(nkWhileStmt, newSymNode(ctx.g.getSysSym(n.info, "true")), loopBody)
   result.info = n.info
 
   if not ctx.stateVarSym.isNil:
@@ -1195,7 +1200,7 @@ proc wrapIntoStateLoop(ctx: var Ctx, n: PNode): PNode =
 
   let gs = newNodeI(nkGotoState, n.info)
   gs.add(ctx.newStateAccess())
-  gs.add(newIntLit(ctx.states.len - 1))
+  gs.add(ctx.g.newIntLit(n.info, ctx.states.len - 1))
 
   var blockBody = newTree(nkStmtList, gs, n)
   if ctx.hasExceptions:
@@ -1205,7 +1210,7 @@ proc wrapIntoStateLoop(ctx: var Ctx, n: PNode): PNode =
   loopBody.add(blockStmt)
 
 proc deleteEmptyStates(ctx: var Ctx) =
-  let goOut = newTree(nkGotoState, newIntLit(-1))
+  let goOut = newTree(nkGotoState, ctx.g.newIntLit(TLineInfo(), -1))
   ctx.exitStateIdx = ctx.newState(goOut, nil)
 
   # Apply new state indexes and mark unused states with -1
@@ -1238,8 +1243,9 @@ proc deleteEmptyStates(ctx: var Ctx) =
     else:
       inc i
 
-proc transformClosureIterator*(fn: PSym, n: PNode): PNode =
+proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode =
   var ctx: Ctx
+  ctx.g = g
   ctx.fn = fn
 
   if getEnvParam(fn).isNil:
@@ -1247,13 +1253,13 @@ proc transformClosureIterator*(fn: PSym, n: PNode): PNode =
     # be handled specially by lambda lifting. Local temp vars (if needed)
     # should folllow the same logic.
     ctx.stateVarSym = newSym(skVar, getIdent(":state"), fn, fn.info)
-    ctx.stateVarSym.typ = createClosureIterStateType(fn)
+    ctx.stateVarSym.typ = g.createClosureIterStateType(fn)
 
   ctx.stateLoopLabel = newSym(skLabel, getIdent(":stateLoop"), fn, fn.info)
   let n = n.toStmtList
 
   discard ctx.newState(n, nil)
-  let gotoOut = newTree(nkGotoState, newIntLit(-1))
+  let gotoOut = newTree(nkGotoState, g.newIntLit(n.info, -1))
 
   # Splitting transformation
   discard ctx.transformClosureIteratorBody(n, gotoOut)
diff --git a/compiler/commands.nim b/compiler/commands.nim
index d8d8ae4b7..09f63f0f5 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -18,7 +18,6 @@ template bootSwitch(name, expr, userString) =
 
 bootSwitch(usedRelease, defined(release), "-d:release")
 bootSwitch(usedGnuReadline, defined(useLinenoise), "-d:useLinenoise")
-bootSwitch(usedNoCaas, defined(noCaas), "-d:noCaas")
 bootSwitch(usedBoehm, defined(boehmgc), "--gc:boehm")
 bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep")
 bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational")
@@ -27,34 +26,24 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none")
 
 import
   os, msgs, options, nversion, condsyms, strutils, extccomp, platform,
-  wordrecg, parseutils, nimblecmd, idents, parseopt, sequtils
+  wordrecg, parseutils, nimblecmd, idents, parseopt, sequtils, configuration
 
 # but some have deps to imported modules. Yay.
 bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc")
-bootSwitch(usedAvoidTimeMachine, noTimeMachine, "-d:avoidTimeMachine")
 bootSwitch(usedNativeStacktrace,
   defined(nativeStackTrace) and nativeStackTraceSupported,
   "-d:nativeStackTrace")
 bootSwitch(usedFFI, hasFFI, "-d:useFFI")
 
-
-proc writeCommandLineUsage*()
-
 type
   TCmdLinePass* = enum
     passCmd1,                 # first pass over the command line
     passCmd2,                 # second pass over the command line
     passPP                    # preprocessor called processCommand()
 
-proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef)
-proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
-                    config: ConfigRef)
-
-# implementation
-
 const
   HelpMessage = "Nim Compiler Version $1 [$2: $3]\n" &
-      "Compiled at $4 $5\n" &
+      "Compiled at $4\n" &
       "Copyright (c) 2006-" & copyrightYear & " by Andreas Rumpf\n"
 
 const
@@ -69,66 +58,68 @@ const
 
 proc getCommandLineDesc(): string =
   result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name,
-                           CPU[platform.hostCPU].name, CompileDate, CompileTime]) &
+                           CPU[platform.hostCPU].name, CompileDate]) &
                            Usage
 
-proc helpOnError(pass: TCmdLinePass) =
+proc helpOnError(conf: ConfigRef; pass: TCmdLinePass) =
   if pass == passCmd1:
-    msgWriteln(getCommandLineDesc(), {msgStdout})
+    msgWriteln(conf, getCommandLineDesc(), {msgStdout})
     msgQuit(0)
 
-proc writeAdvancedUsage(pass: TCmdLinePass) =
+proc writeAdvancedUsage(conf: ConfigRef; pass: TCmdLinePass) =
   if pass == passCmd1:
-    msgWriteln(`%`(HelpMessage, [VersionAsString,
+    msgWriteln(conf, (HelpMessage % [VersionAsString,
                                  platform.OS[platform.hostOS].name,
-                                 CPU[platform.hostCPU].name, CompileDate, CompileTime]) &
+                                 CPU[platform.hostCPU].name, CompileDate]) &
                                  AdvancedUsage,
                {msgStdout})
     msgQuit(0)
 
-proc writeFullhelp(pass: TCmdLinePass) =
+proc writeFullhelp(conf: ConfigRef; pass: TCmdLinePass) =
   if pass == passCmd1:
-    msgWriteln(`%`(HelpMessage, [VersionAsString,
+    msgWriteln(conf, `%`(HelpMessage, [VersionAsString,
                                  platform.OS[platform.hostOS].name,
-                                 CPU[platform.hostCPU].name, CompileDate, CompileTime]) &
+                                 CPU[platform.hostCPU].name, CompileDate]) &
                                  Usage & AdvancedUsage,
                {msgStdout})
     msgQuit(0)
 
-proc writeVersionInfo(pass: TCmdLinePass) =
+proc writeVersionInfo(conf: ConfigRef; pass: TCmdLinePass) =
   if pass == passCmd1:
-    msgWriteln(`%`(HelpMessage, [VersionAsString,
+    msgWriteln(conf, `%`(HelpMessage, [VersionAsString,
                                  platform.OS[platform.hostOS].name,
-                                 CPU[platform.hostCPU].name, CompileDate, CompileTime]),
+                                 CPU[platform.hostCPU].name, CompileDate]),
                {msgStdout})
 
     const gitHash = gorge("git log -n 1 --format=%H").strip
     when gitHash.len == 40:
-      msgWriteln("git hash: " & gitHash, {msgStdout})
+      msgWriteln(conf, "git hash: " & gitHash, {msgStdout})
 
-    msgWriteln("active boot switches:" & usedRelease & usedAvoidTimeMachine &
-      usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas &
+    msgWriteln(conf, "active boot switches:" & usedRelease &
+      usedTinyC & usedGnuReadline & usedNativeStacktrace &
       usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedGoGC & usedNoGC,
                {msgStdout})
     msgQuit(0)
 
-var
-  helpWritten: bool
-
-proc writeCommandLineUsage() =
+proc writeCommandLineUsage*(conf: ConfigRef; helpWritten: var bool) =
   if not helpWritten:
-    msgWriteln(getCommandLineDesc(), {msgStdout})
+    msgWriteln(conf, getCommandLineDesc(), {msgStdout})
     helpWritten = true
 
 proc addPrefix(switch: string): string =
   if len(switch) == 1: result = "-" & switch
   else: result = "--" & switch
 
-proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) =
-  if switch == " ": localError(info, errInvalidCmdLineOption, "-")
-  else: localError(info, errInvalidCmdLineOption, addPrefix(switch))
+const
+  errInvalidCmdLineOption = "invalid command line option: '$1'"
+  errOnOrOffExpectedButXFound = "'on' or 'off' expected, but '$1' found"
+  errOnOffOrListExpectedButXFound = "'on', 'off' or 'list' expected, but '$1' found"
+
+proc invalidCmdLineOption(conf: ConfigRef; pass: TCmdLinePass, switch: string, info: TLineInfo) =
+  if switch == " ": localError(conf, info, errInvalidCmdLineOption % "-")
+  else: localError(conf, info, errInvalidCmdLineOption % addPrefix(switch))
 
-proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
+proc splitSwitch(conf: ConfigRef; switch: string, cmd, arg: var string, pass: TCmdLinePass,
                  info: TLineInfo) =
   cmd = ""
   var i = 0
@@ -141,46 +132,41 @@ proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
     inc(i)
   if i >= len(switch): arg = ""
   elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1)
-  else: invalidCmdLineOption(pass, switch, info)
+  else: invalidCmdLineOption(conf, pass, switch, info)
 
-proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass,
+proc processOnOffSwitch(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass,
                         info: TLineInfo) =
   case arg.normalize
-  of "on": gOptions = gOptions + op
-  of "off": gOptions = gOptions - op
-  else: localError(info, errOnOrOffExpectedButXFound, arg)
+  of "on": conf.options = conf.options + op
+  of "off": conf.options = conf.options - op
+  else: localError(conf, info, errOnOrOffExpectedButXFound % arg)
 
-proc processOnOffSwitchOrList(op: TOptions, arg: string, pass: TCmdLinePass,
+proc processOnOffSwitchOrList(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass,
                               info: TLineInfo): bool =
   result = false
   case arg.normalize
-  of "on": gOptions = gOptions + op
-  of "off": gOptions = gOptions - op
-  else:
-    if arg == "list":
-      result = true
-    else:
-      localError(info, errOnOffOrListExpectedButXFound, arg)
+  of "on": conf.options = conf.options + op
+  of "off": conf.options = conf.options - op
+  of "list": result = true
+  else: localError(conf, info, errOnOffOrListExpectedButXFound % arg)
 
-proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass,
+proc processOnOffSwitchG(conf: ConfigRef; op: TGlobalOptions, arg: string, pass: TCmdLinePass,
                          info: TLineInfo) =
   case arg.normalize
-  of "on": gGlobalOptions = gGlobalOptions + op
-  of "off": gGlobalOptions = gGlobalOptions - op
-  else: localError(info, errOnOrOffExpectedButXFound, arg)
-
-proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
-  if arg == "": localError(info, errCmdLineArgExpected, addPrefix(switch))
+  of "on": conf.globalOptions = conf.globalOptions + op
+  of "off": conf.globalOptions = conf.globalOptions - op
+  else: localError(conf, info, errOnOrOffExpectedButXFound % arg)
 
-proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
-  if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch))
+proc expectArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
+  if arg == "":
+    localError(conf, info, "argument for command line option expected: '$1'" % addPrefix(switch))
 
-var
-  enableNotes: TNoteKinds
-  disableNotes: TNoteKinds
+proc expectNoArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
+  if arg != "":
+    localError(conf, info, "invalid argument for command line option: '$1'" % addPrefix(switch))
 
 proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
-                         info: TLineInfo; orig: string) =
+                         info: TLineInfo; orig: string; conf: ConfigRef) =
   var id = ""  # arg = "X]:on|off"
   var i = 0
   var n = hintMin
@@ -188,122 +174,127 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
     add(id, arg[i])
     inc(i)
   if i < len(arg) and (arg[i] == ']'): inc(i)
-  else: invalidCmdLineOption(pass, orig, info)
+  else: invalidCmdLineOption(conf, pass, orig, info)
   if i < len(arg) and (arg[i] in {':', '='}): inc(i)
-  else: invalidCmdLineOption(pass, orig, info)
+  else: invalidCmdLineOption(conf, pass, orig, info)
   if state == wHint:
-    let x = findStr(msgs.HintsToStr, id)
+    let x = findStr(configuration.HintsToStr, id)
     if x >= 0: n = TNoteKind(x + ord(hintMin))
-    else: localError(info, "unknown hint: " & id)
+    else: localError(conf, info, "unknown hint: " & id)
   else:
-    let x = findStr(msgs.WarningsToStr, id)
+    let x = findStr(configuration.WarningsToStr, id)
     if x >= 0: n = TNoteKind(x + ord(warnMin))
-    else: localError(info, "unknown warning: " & id)
+    else: localError(conf, info, "unknown warning: " & id)
   case substr(arg, i).normalize
   of "on":
-    incl(gNotes, n)
-    incl(gMainPackageNotes, n)
-    incl(enableNotes, n)
+    incl(conf.notes, n)
+    incl(conf.mainPackageNotes, n)
+    incl(conf.enableNotes, n)
   of "off":
-    excl(gNotes, n)
-    excl(gMainPackageNotes, n)
-    incl(disableNotes, n)
-    excl(ForeignPackageNotes, n)
-  else: localError(info, errOnOrOffExpectedButXFound, arg)
-
-proc processCompile(filename: string) =
-  var found = findFile(filename)
+    excl(conf.notes, n)
+    excl(conf.mainPackageNotes, n)
+    incl(conf.disableNotes, n)
+    excl(conf.foreignPackageNotes, n)
+  else: localError(conf, info, errOnOrOffExpectedButXFound % arg)
+
+proc processCompile(conf: ConfigRef; filename: string) =
+  var found = findFile(conf, filename)
   if found == "": found = filename
-  extccomp.addExternalFileToCompile(found)
+  extccomp.addExternalFileToCompile(conf, found)
+
+const
+  errNoneBoehmRefcExpectedButXFound = "'none', 'boehm' or 'refc' expected, but '$1' found"
+  errNoneSpeedOrSizeExpectedButXFound = "'none', 'speed' or 'size' expected, but '$1' found"
+  errGuiConsoleOrLibExpectedButXFound = "'gui', 'console' or 'lib' expected, but '$1' found"
 
-proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
+proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo): bool =
   case switch.normalize
   of "gc":
     case arg.normalize
-    of "boehm":        result = gSelectedGC == gcBoehm
-    of "refc":         result = gSelectedGC == gcRefc
-    of "v2":           result = gSelectedGC == gcV2
-    of "markandsweep": result = gSelectedGC == gcMarkAndSweep
-    of "generational": result = gSelectedGC == gcGenerational
-    of "go":           result = gSelectedGC == gcGo
-    of "none":         result = gSelectedGC == gcNone
-    of "stack", "regions": result = gSelectedGC == gcRegions
-    else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
+    of "boehm":        result = conf.selectedGC == gcBoehm
+    of "refc":         result = conf.selectedGC == gcRefc
+    of "v2":           result = conf.selectedGC == gcV2
+    of "markandsweep": result = conf.selectedGC == gcMarkAndSweep
+    of "generational": result = conf.selectedGC == gcGenerational
+    of "go":           result = conf.selectedGC == gcGo
+    of "none":         result = conf.selectedGC == gcNone
+    of "stack", "regions": result = conf.selectedGC == gcRegions
+    else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
   of "opt":
     case arg.normalize
-    of "speed": result = contains(gOptions, optOptimizeSpeed)
-    of "size": result = contains(gOptions, optOptimizeSize)
-    of "none": result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {}
-    else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
-  of "verbosity": result = $gVerbosity == arg
+    of "speed": result = contains(conf.options, optOptimizeSpeed)
+    of "size": result = contains(conf.options, optOptimizeSize)
+    of "none": result = conf.options * {optOptimizeSpeed, optOptimizeSize} == {}
+    else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
+  of "verbosity": result = $conf.verbosity == arg
   of "app":
     case arg.normalize
-    of "gui":       result = contains(gGlobalOptions, optGenGuiApp)
-    of "console":   result = not contains(gGlobalOptions, optGenGuiApp)
-    of "lib":       result = contains(gGlobalOptions, optGenDynLib) and
-                      not contains(gGlobalOptions, optGenGuiApp)
-    of "staticlib": result = contains(gGlobalOptions, optGenStaticLib) and
-                      not contains(gGlobalOptions, optGenGuiApp)
-    else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg)
+    of "gui":       result = contains(conf.globalOptions, optGenGuiApp)
+    of "console":   result = not contains(conf.globalOptions, optGenGuiApp)
+    of "lib":       result = contains(conf.globalOptions, optGenDynLib) and
+                      not contains(conf.globalOptions, optGenGuiApp)
+    of "staticlib": result = contains(conf.globalOptions, optGenStaticLib) and
+                      not contains(conf.globalOptions, optGenGuiApp)
+    else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
   of "dynliboverride":
-    result = isDynlibOverride(arg)
-  else: invalidCmdLineOption(passCmd1, switch, info)
+    result = isDynlibOverride(conf, arg)
+  else: invalidCmdLineOption(conf, passCmd1, switch, info)
 
-proc testCompileOption*(switch: string, info: TLineInfo): bool =
+proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool =
   case switch.normalize
-  of "debuginfo": result = contains(gGlobalOptions, optCDebug)
-  of "compileonly", "c": result = contains(gGlobalOptions, optCompileOnly)
-  of "nolinking": result = contains(gGlobalOptions, optNoLinking)
-  of "nomain": result = contains(gGlobalOptions, optNoMain)
-  of "forcebuild", "f": result = contains(gGlobalOptions, optForceFullMake)
-  of "warnings", "w": result = contains(gOptions, optWarns)
-  of "hints": result = contains(gOptions, optHints)
-  of "threadanalysis": result = contains(gGlobalOptions, optThreadAnalysis)
-  of "stacktrace": result = contains(gOptions, optStackTrace)
-  of "linetrace": result = contains(gOptions, optLineTrace)
-  of "debugger": result = contains(gOptions, optEndb)
-  of "profiler": result = contains(gOptions, optProfiler)
-  of "memtracker": result = contains(gOptions, optMemTracker)
-  of "checks", "x": result = gOptions * ChecksOptions == ChecksOptions
+  of "debuginfo": result = contains(conf.globalOptions, optCDebug)
+  of "compileonly", "c": result = contains(conf.globalOptions, optCompileOnly)
+  of "nolinking": result = contains(conf.globalOptions, optNoLinking)
+  of "nomain": result = contains(conf.globalOptions, optNoMain)
+  of "forcebuild", "f": result = contains(conf.globalOptions, optForceFullMake)
+  of "warnings", "w": result = contains(conf.options, optWarns)
+  of "hints": result = contains(conf.options, optHints)
+  of "threadanalysis": result = contains(conf.globalOptions, optThreadAnalysis)
+  of "stacktrace": result = contains(conf.options, optStackTrace)
+  of "linetrace": result = contains(conf.options, optLineTrace)
+  of "debugger": result = contains(conf.options, optEndb)
+  of "profiler": result = contains(conf.options, optProfiler)
+  of "memtracker": result = contains(conf.options, optMemTracker)
+  of "checks", "x": result = conf.options * ChecksOptions == ChecksOptions
   of "floatchecks":
-    result = gOptions * {optNaNCheck, optInfCheck} == {optNaNCheck, optInfCheck}
-  of "infchecks": result = contains(gOptions, optInfCheck)
-  of "nanchecks": result = contains(gOptions, optNaNCheck)
-  of "nilchecks": result = contains(gOptions, optNilCheck)
-  of "objchecks": result = contains(gOptions, optObjCheck)
-  of "fieldchecks": result = contains(gOptions, optFieldCheck)
-  of "rangechecks": result = contains(gOptions, optRangeCheck)
-  of "boundchecks": result = contains(gOptions, optBoundsCheck)
-  of "overflowchecks": result = contains(gOptions, optOverflowCheck)
-  of "movechecks": result = contains(gOptions, optMoveCheck)
-  of "linedir": result = contains(gOptions, optLineDir)
-  of "assertions", "a": result = contains(gOptions, optAssert)
-  of "run", "r": result = contains(gGlobalOptions, optRun)
-  of "symbolfiles": result = gSymbolFiles != disabledSf
-  of "genscript": result = contains(gGlobalOptions, optGenScript)
-  of "threads": result = contains(gGlobalOptions, optThreads)
-  of "taintmode": result = contains(gGlobalOptions, optTaintMode)
-  of "tlsemulation": result = contains(gGlobalOptions, optTlsEmulation)
-  of "implicitstatic": result = contains(gOptions, optImplicitStatic)
-  of "patterns": result = contains(gOptions, optPatterns)
-  of "excessivestacktrace": result = contains(gGlobalOptions, optExcessiveStackTrace)
-  else: invalidCmdLineOption(passCmd1, switch, info)
-
-proc processPath(path: string, info: TLineInfo,
+    result = conf.options * {optNaNCheck, optInfCheck} == {optNaNCheck, optInfCheck}
+  of "infchecks": result = contains(conf.options, optInfCheck)
+  of "nanchecks": result = contains(conf.options, optNaNCheck)
+  of "nilchecks": result = contains(conf.options, optNilCheck)
+  of "objchecks": result = contains(conf.options, optObjCheck)
+  of "fieldchecks": result = contains(conf.options, optFieldCheck)
+  of "rangechecks": result = contains(conf.options, optRangeCheck)
+  of "boundchecks": result = contains(conf.options, optBoundsCheck)
+  of "overflowchecks": result = contains(conf.options, optOverflowCheck)
+  of "movechecks": result = contains(conf.options, optMoveCheck)
+  of "linedir": result = contains(conf.options, optLineDir)
+  of "assertions", "a": result = contains(conf.options, optAssert)
+  of "run", "r": result = contains(conf.globalOptions, optRun)
+  of "symbolfiles": result = conf.symbolFiles != disabledSf
+  of "genscript": result = contains(conf.globalOptions, optGenScript)
+  of "threads": result = contains(conf.globalOptions, optThreads)
+  of "taintmode": result = contains(conf.globalOptions, optTaintMode)
+  of "tlsemulation": result = contains(conf.globalOptions, optTlsEmulation)
+  of "implicitstatic": result = contains(conf.options, optImplicitStatic)
+  of "patterns": result = contains(conf.options, optPatterns)
+  of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace)
+  else: invalidCmdLineOption(conf, passCmd1, switch, info)
+
+proc processPath(conf: ConfigRef; path: string, info: TLineInfo,
                  notRelativeToProj = false): string =
   let p = if os.isAbsolute(path) or '$' in path:
             path
           elif notRelativeToProj:
             getCurrentDir() / path
           else:
-            options.gProjectPath / path
+            conf.projectPath / path
   try:
-    result = pathSubs(p, info.toFullPath().splitFile().dir)
+    result = pathSubs(conf, p, info.toFullPath().splitFile().dir)
   except ValueError:
-    localError(info, "invalid path: " & p)
+    localError(conf, info, "invalid path: " & p)
     result = p
 
-proc processCfgPath(path: string, info: TLineInfo): string =
+proc processCfgPath(conf: ConfigRef; path: string, info: TLineInfo): string =
   let path = if path[0] == '"': strutils.unescape(path) else: path
   let basedir = info.toFullPath().splitFile().dir
   let p = if os.isAbsolute(path) or '$' in path:
@@ -311,431 +302,436 @@ proc processCfgPath(path: string, info: TLineInfo): string =
           else:
             basedir / path
   try:
-    result = pathSubs(p, basedir)
+    result = pathSubs(conf, p, basedir)
   except ValueError:
-    localError(info, "invalid path: " & p)
+    localError(conf, info, "invalid path: " & p)
     result = p
 
-proc trackDirty(arg: string, info: TLineInfo) =
+const
+  errInvalidNumber = "$1 is not a valid number"
+
+proc trackDirty(conf: ConfigRef; arg: string, info: TLineInfo) =
   var a = arg.split(',')
-  if a.len != 4: localError(info, errTokenExpected,
-                            "DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN")
+  if a.len != 4: localError(conf, info,
+                            "DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN expected")
   var line, column: int
   if parseUtils.parseInt(a[2], line) <= 0:
-    localError(info, errInvalidNumber, a[1])
+    localError(conf, info, errInvalidNumber % a[1])
   if parseUtils.parseInt(a[3], column) <= 0:
-    localError(info, errInvalidNumber, a[2])
+    localError(conf, info, errInvalidNumber % a[2])
 
-  let dirtyOriginalIdx = a[1].fileInfoIdx
+  let dirtyOriginalIdx = fileInfoIdx(conf, a[1])
   if dirtyOriginalIdx.int32 >= 0:
     msgs.setDirtyFile(dirtyOriginalIdx, a[0])
 
   gTrackPos = newLineInfo(dirtyOriginalIdx, line, column)
 
-proc track(arg: string, info: TLineInfo) =
+proc track(conf: ConfigRef; arg: string, info: TLineInfo) =
   var a = arg.split(',')
-  if a.len != 3: localError(info, errTokenExpected, "FILE,LINE,COLUMN")
+  if a.len != 3: localError(conf, info, "FILE,LINE,COLUMN expected")
   var line, column: int
   if parseUtils.parseInt(a[1], line) <= 0:
-    localError(info, errInvalidNumber, a[1])
+    localError(conf, info, errInvalidNumber % a[1])
   if parseUtils.parseInt(a[2], column) <= 0:
-    localError(info, errInvalidNumber, a[2])
-  gTrackPos = newLineInfo(a[0], line, column)
+    localError(conf, info, errInvalidNumber % a[2])
+  gTrackPos = newLineInfo(conf, a[0], line, column)
 
-proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
+proc dynlibOverride(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   if pass in {passCmd2, passPP}:
-    expectArg(switch, arg, pass, info)
-    options.inclDynlibOverride(arg)
+    expectArg(conf, switch, arg, pass, info)
+    options.inclDynlibOverride(conf, arg)
 
-proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
-                   config: ConfigRef) =
+proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
+                    conf: ConfigRef) =
   var
     theOS: TSystemOS
     cpu: TSystemCPU
     key, val: string
   case switch.normalize
   of "path", "p":
-    expectArg(switch, arg, pass, info)
-    addPath(if pass == passPP: processCfgPath(arg, info) else: processPath(arg, info), info)
+    expectArg(conf, switch, arg, pass, info)
+    addPath(conf, if pass == passPP: processCfgPath(conf, arg, info) else: processPath(conf, arg, info), info)
   of "nimblepath", "babelpath":
     # keep the old name for compat
-    if pass in {passCmd2, passPP} and not options.gNoNimblePath:
-      expectArg(switch, arg, pass, info)
-      var path = processPath(arg, info, notRelativeToProj=true)
+    if pass in {passCmd2, passPP} and optNoNimblePath notin conf.globalOptions:
+      expectArg(conf, switch, arg, pass, info)
+      var path = processPath(conf, arg, info, notRelativeToProj=true)
       let nimbleDir = getEnv("NIMBLE_DIR")
       if nimbleDir.len > 0 and pass == passPP: path = nimbleDir / "pkgs"
-      nimblePath(path, info)
+      nimblePath(conf, path, info)
   of "nonimblepath", "nobabelpath":
-    expectNoArg(switch, arg, pass, info)
-    disableNimblePath()
+    expectNoArg(conf, switch, arg, pass, info)
+    disableNimblePath(conf)
   of "excludepath":
-    expectArg(switch, arg, pass, info)
-    let path = processPath(arg, info)
+    expectArg(conf, switch, arg, pass, info)
+    let path = processPath(conf, arg, info)
 
-    options.searchPaths.keepItIf( cmpPaths(it, path) != 0 )
-    options.lazyPaths.keepItIf( cmpPaths(it, path) != 0 )
+    conf.searchPaths.keepItIf(cmpPaths(it, path) != 0)
+    conf.lazyPaths.keepItIf(cmpPaths(it, path) != 0)
 
     if (len(path) > 0) and (path[len(path) - 1] == DirSep):
       let strippedPath = path[0 .. (len(path) - 2)]
-      options.searchPaths.keepItIf( cmpPaths(it, strippedPath) != 0 )
-      options.lazyPaths.keepItIf( cmpPaths(it, strippedPath) != 0 )
+      conf.searchPaths.keepItIf(cmpPaths(it, strippedPath) != 0)
+      conf.lazyPaths.keepItIf(cmpPaths(it, strippedPath) != 0)
   of "nimcache":
-    expectArg(switch, arg, pass, info)
-    options.nimcacheDir = processPath(arg, info, true)
+    expectArg(conf, switch, arg, pass, info)
+    conf.nimcacheDir = processPath(conf, arg, info, true)
   of "out", "o":
-    expectArg(switch, arg, pass, info)
-    options.outFile = arg
+    expectArg(conf, switch, arg, pass, info)
+    conf.outFile = arg
   of "docseesrcurl":
-    expectArg(switch, arg, pass, info)
-    options.docSeeSrcUrl = arg
+    expectArg(conf, switch, arg, pass, info)
+    conf.docSeeSrcUrl = arg
   of "mainmodule", "m":
     discard "allow for backwards compatibility, but don't do anything"
   of "define", "d":
-    expectArg(switch, arg, pass, info)
+    expectArg(conf, switch, arg, pass, info)
     if {':', '='} in arg:
-      splitSwitch(arg, key, val, pass, info)
-      defineSymbol(key, val)
+      splitSwitch(conf, arg, key, val, pass, info)
+      defineSymbol(conf.symbols, key, val)
     else:
-      defineSymbol(arg)
+      defineSymbol(conf.symbols, arg)
   of "undef", "u":
-    expectArg(switch, arg, pass, info)
-    undefSymbol(arg)
+    expectArg(conf, switch, arg, pass, info)
+    undefSymbol(conf.symbols, arg)
   of "symbol":
-    expectArg(switch, arg, pass, info)
+    expectArg(conf, switch, arg, pass, info)
     # deprecated, do nothing
   of "compile":
-    expectArg(switch, arg, pass, info)
-    if pass in {passCmd2, passPP}: processCompile(arg)
+    expectArg(conf, switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: processCompile(conf, arg)
   of "link":
-    expectArg(switch, arg, pass, info)
-    if pass in {passCmd2, passPP}: addExternalFileToLink(arg)
+    expectArg(conf, switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: addExternalFileToLink(conf, arg)
   of "debuginfo":
-    expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optCDebug)
+    expectNoArg(conf, switch, arg, pass, info)
+    incl(conf.globalOptions, optCDebug)
   of "embedsrc":
-    expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optEmbedOrigSrc)
+    expectNoArg(conf, switch, arg, pass, info)
+    incl(conf.globalOptions, optEmbedOrigSrc)
   of "compileonly", "c":
-    expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optCompileOnly)
+    expectNoArg(conf, switch, arg, pass, info)
+    incl(conf.globalOptions, optCompileOnly)
   of "nolinking":
-    expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optNoLinking)
+    expectNoArg(conf, switch, arg, pass, info)
+    incl(conf.globalOptions, optNoLinking)
   of "nomain":
-    expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optNoMain)
+    expectNoArg(conf, switch, arg, pass, info)
+    incl(conf.globalOptions, optNoMain)
   of "forcebuild", "f":
-    expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optForceFullMake)
+    expectNoArg(conf, switch, arg, pass, info)
+    incl(conf.globalOptions, optForceFullMake)
   of "project":
-    expectNoArg(switch, arg, pass, info)
-    gWholeProject = true
+    expectNoArg(conf, switch, arg, pass, info)
+    incl conf.globalOptions, optWholeProject
   of "gc":
-    expectArg(switch, arg, pass, info)
+    expectArg(conf, switch, arg, pass, info)
     case arg.normalize
     of "boehm":
-      gSelectedGC = gcBoehm
-      defineSymbol("boehmgc")
+      conf.selectedGC = gcBoehm
+      defineSymbol(conf.symbols, "boehmgc")
     of "refc":
-      gSelectedGC = gcRefc
+      conf.selectedGC = gcRefc
     of "v2":
-      gSelectedGC = gcV2
+      conf.selectedGC = gcV2
     of "markandsweep":
-      gSelectedGC = gcMarkAndSweep
-      defineSymbol("gcmarkandsweep")
+      conf.selectedGC = gcMarkAndSweep
+      defineSymbol(conf.symbols, "gcmarkandsweep")
     of "generational":
-      gSelectedGC = gcGenerational
-      defineSymbol("gcgenerational")
+      conf.selectedGC = gcGenerational
+      defineSymbol(conf.symbols, "gcgenerational")
     of "go":
-      gSelectedGC = gcGo
-      defineSymbol("gogc")
+      conf.selectedGC = gcGo
+      defineSymbol(conf.symbols, "gogc")
     of "none":
-      gSelectedGC = gcNone
-      defineSymbol("nogc")
+      conf.selectedGC = gcNone
+      defineSymbol(conf.symbols, "nogc")
     of "stack", "regions":
-      gSelectedGC= gcRegions
-      defineSymbol("gcregions")
-    else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
+      conf.selectedGC= gcRegions
+      defineSymbol(conf.symbols, "gcregions")
+    else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
   of "warnings", "w":
-    if processOnOffSwitchOrList({optWarns}, arg, pass, info): listWarnings()
-  of "warning": processSpecificNote(arg, wWarning, pass, info, switch)
-  of "hint": processSpecificNote(arg, wHint, pass, info, switch)
+    if processOnOffSwitchOrList(conf, {optWarns}, arg, pass, info): listWarnings(conf)
+  of "warning": processSpecificNote(arg, wWarning, pass, info, switch, conf)
+  of "hint": processSpecificNote(arg, wHint, pass, info, switch, conf)
   of "hints":
-    if processOnOffSwitchOrList({optHints}, arg, pass, info): listHints()
-  of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
-  of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info)
-  of "excessivestacktrace": processOnOffSwitchG({optExcessiveStackTrace}, arg, pass, info)
-  of "linetrace": processOnOffSwitch({optLineTrace}, arg, pass, info)
+    if processOnOffSwitchOrList(conf, {optHints}, arg, pass, info): listHints(conf)
+  of "threadanalysis": processOnOffSwitchG(conf, {optThreadAnalysis}, arg, pass, info)
+  of "stacktrace": processOnOffSwitch(conf, {optStackTrace}, arg, pass, info)
+  of "excessivestacktrace": processOnOffSwitchG(conf, {optExcessiveStackTrace}, arg, pass, info)
+  of "linetrace": processOnOffSwitch(conf, {optLineTrace}, arg, pass, info)
   of "debugger":
     case arg.normalize
     of "on", "endb":
-      gOptions.incl optEndb
-      defineSymbol("endb")
+      conf.options.incl optEndb
+      defineSymbol(conf.symbols, "endb")
     of "off":
-      gOptions.excl optEndb
-      undefSymbol("endb")
+      conf.options.excl optEndb
+      undefSymbol(conf.symbols, "endb")
     of "native", "gdb":
-      incl(gGlobalOptions, optCDebug)
-      gOptions = gOptions + {optLineDir} - {optEndb}
-      defineSymbol("nimTypeNames", nil) # type names are used in gdb pretty printing
-      undefSymbol("endb")
+      incl(conf.globalOptions, optCDebug)
+      conf.options = conf.options + {optLineDir} - {optEndb}
+      defineSymbol(conf.symbols, "nimTypeNames") # type names are used in gdb pretty printing
+      undefSymbol(conf.symbols, "endb")
     else:
-      localError(info, "expected endb|gdb but found " & arg)
+      localError(conf, info, "expected endb|gdb but found " & arg)
   of "profiler":
-    processOnOffSwitch({optProfiler}, arg, pass, info)
-    if optProfiler in gOptions: defineSymbol("profiler")
-    else: undefSymbol("profiler")
+    processOnOffSwitch(conf, {optProfiler}, arg, pass, info)
+    if optProfiler in conf.options: defineSymbol(conf.symbols, "profiler")
+    else: undefSymbol(conf.symbols, "profiler")
   of "memtracker":
-    processOnOffSwitch({optMemTracker}, arg, pass, info)
-    if optMemTracker in gOptions: defineSymbol("memtracker")
-    else: undefSymbol("memtracker")
+    processOnOffSwitch(conf, {optMemTracker}, arg, pass, info)
+    if optMemTracker in conf.options: defineSymbol(conf.symbols, "memtracker")
+    else: undefSymbol(conf.symbols, "memtracker")
   of "hotcodereloading":
-    processOnOffSwitch({optHotCodeReloading}, arg, pass, info)
-    if optHotCodeReloading in gOptions: defineSymbol("hotcodereloading")
-    else: undefSymbol("hotcodereloading")
+    processOnOffSwitch(conf, {optHotCodeReloading}, arg, pass, info)
+    if optHotCodeReloading in conf.options: defineSymbol(conf.symbols, "hotcodereloading")
+    else: undefSymbol(conf.symbols, "hotcodereloading")
   of "oldnewlines":
     case arg.normalize
     of "on":
-      options.gOldNewlines = true
-      defineSymbol("nimOldNewlines")
+      conf.oldNewlines = true
+      defineSymbol(conf.symbols, "nimOldNewlines")
     of "off":
-      options.gOldNewlines = false
-      undefSymbol("nimOldNewlines")
+      conf.oldNewlines = false
+      undefSymbol(conf.symbols, "nimOldNewlines")
     else:
-      localError(info, errOnOrOffExpectedButXFound, arg)
-  of "laxstrings": processOnOffSwitch({optLaxStrings}, arg, pass, info)
-  of "checks", "x": processOnOffSwitch(ChecksOptions, arg, pass, info)
+      localError(conf, info, errOnOrOffExpectedButXFound % arg)
+  of "laxstrings": processOnOffSwitch(conf, {optLaxStrings}, arg, pass, info)
+  of "checks", "x": processOnOffSwitch(conf, ChecksOptions, arg, pass, info)
   of "floatchecks":
-    processOnOffSwitch({optNaNCheck, optInfCheck}, arg, pass, info)
-  of "infchecks": processOnOffSwitch({optInfCheck}, arg, pass, info)
-  of "nanchecks": processOnOffSwitch({optNaNCheck}, arg, pass, info)
-  of "nilchecks": processOnOffSwitch({optNilCheck}, arg, pass, info)
-  of "objchecks": processOnOffSwitch({optObjCheck}, arg, pass, info)
-  of "fieldchecks": processOnOffSwitch({optFieldCheck}, arg, pass, info)
-  of "rangechecks": processOnOffSwitch({optRangeCheck}, arg, pass, info)
-  of "boundchecks": processOnOffSwitch({optBoundsCheck}, arg, pass, info)
-  of "overflowchecks": processOnOffSwitch({optOverflowCheck}, arg, pass, info)
-  of "movechecks": processOnOffSwitch({optMoveCheck}, arg, pass, info)
-  of "linedir": processOnOffSwitch({optLineDir}, arg, pass, info)
-  of "assertions", "a": processOnOffSwitch({optAssert}, arg, pass, info)
+    processOnOffSwitch(conf, {optNaNCheck, optInfCheck}, arg, pass, info)
+  of "infchecks": processOnOffSwitch(conf, {optInfCheck}, arg, pass, info)
+  of "nanchecks": processOnOffSwitch(conf, {optNaNCheck}, arg, pass, info)
+  of "nilchecks": processOnOffSwitch(conf, {optNilCheck}, arg, pass, info)
+  of "objchecks": processOnOffSwitch(conf, {optObjCheck}, arg, pass, info)
+  of "fieldchecks": processOnOffSwitch(conf, {optFieldCheck}, arg, pass, info)
+  of "rangechecks": processOnOffSwitch(conf, {optRangeCheck}, arg, pass, info)
+  of "boundchecks": processOnOffSwitch(conf, {optBoundsCheck}, arg, pass, info)
+  of "overflowchecks": processOnOffSwitch(conf, {optOverflowCheck}, arg, pass, info)
+  of "movechecks": processOnOffSwitch(conf, {optMoveCheck}, arg, pass, info)
+  of "linedir": processOnOffSwitch(conf, {optLineDir}, arg, pass, info)
+  of "assertions", "a": processOnOffSwitch(conf, {optAssert}, arg, pass, info)
   of "deadcodeelim": discard # deprecated, dead code elim always on
   of "threads":
-    processOnOffSwitchG({optThreads}, arg, pass, info)
-    #if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe)
-  of "tlsemulation": processOnOffSwitchG({optTlsEmulation}, arg, pass, info)
-  of "taintmode": processOnOffSwitchG({optTaintMode}, arg, pass, info)
+    processOnOffSwitchG(conf, {optThreads}, arg, pass, info)
+    #if optThreads in conf.globalOptions: incl(conf.notes, warnGcUnsafe)
+  of "tlsemulation": processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info)
+  of "taintmode": processOnOffSwitchG(conf, {optTaintMode}, arg, pass, info)
   of "implicitstatic":
-    processOnOffSwitch({optImplicitStatic}, arg, pass, info)
+    processOnOffSwitch(conf, {optImplicitStatic}, arg, pass, info)
   of "patterns":
-    processOnOffSwitch({optPatterns}, arg, pass, info)
+    processOnOffSwitch(conf, {optPatterns}, arg, pass, info)
   of "opt":
-    expectArg(switch, arg, pass, info)
+    expectArg(conf, switch, arg, pass, info)
     case arg.normalize
     of "speed":
-      incl(gOptions, optOptimizeSpeed)
-      excl(gOptions, optOptimizeSize)
+      incl(conf.options, optOptimizeSpeed)
+      excl(conf.options, optOptimizeSize)
     of "size":
-      excl(gOptions, optOptimizeSpeed)
-      incl(gOptions, optOptimizeSize)
+      excl(conf.options, optOptimizeSpeed)
+      incl(conf.options, optOptimizeSize)
     of "none":
-      excl(gOptions, optOptimizeSpeed)
-      excl(gOptions, optOptimizeSize)
-    else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
+      excl(conf.options, optOptimizeSpeed)
+      excl(conf.options, optOptimizeSize)
+    else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
   of "app":
-    expectArg(switch, arg, pass, info)
+    expectArg(conf, switch, arg, pass, info)
     case arg.normalize
     of "gui":
-      incl(gGlobalOptions, optGenGuiApp)
-      defineSymbol("executable")
-      defineSymbol("guiapp")
+      incl(conf.globalOptions, optGenGuiApp)
+      defineSymbol(conf.symbols, "executable")
+      defineSymbol(conf.symbols, "guiapp")
     of "console":
-      excl(gGlobalOptions, optGenGuiApp)
-      defineSymbol("executable")
-      defineSymbol("consoleapp")
+      excl(conf.globalOptions, optGenGuiApp)
+      defineSymbol(conf.symbols, "executable")
+      defineSymbol(conf.symbols, "consoleapp")
     of "lib":
-      incl(gGlobalOptions, optGenDynLib)
-      excl(gGlobalOptions, optGenGuiApp)
-      defineSymbol("library")
-      defineSymbol("dll")
+      incl(conf.globalOptions, optGenDynLib)
+      excl(conf.globalOptions, optGenGuiApp)
+      defineSymbol(conf.symbols, "library")
+      defineSymbol(conf.symbols, "dll")
     of "staticlib":
-      incl(gGlobalOptions, optGenStaticLib)
-      excl(gGlobalOptions, optGenGuiApp)
-      defineSymbol("library")
-      defineSymbol("staticlib")
-    else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg)
+      incl(conf.globalOptions, optGenStaticLib)
+      excl(conf.globalOptions, optGenGuiApp)
+      defineSymbol(conf.symbols, "library")
+      defineSymbol(conf.symbols, "staticlib")
+    else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
   of "passc", "t":
-    expectArg(switch, arg, pass, info)
-    if pass in {passCmd2, passPP}: extccomp.addCompileOptionCmd(arg)
+    expectArg(conf, switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: extccomp.addCompileOptionCmd(conf, arg)
   of "passl", "l":
-    expectArg(switch, arg, pass, info)
-    if pass in {passCmd2, passPP}: extccomp.addLinkOptionCmd(arg)
+    expectArg(conf, switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: extccomp.addLinkOptionCmd(conf, arg)
   of "cincludes":
-    expectArg(switch, arg, pass, info)
-    if pass in {passCmd2, passPP}: cIncludes.add arg.processPath(info)
+    expectArg(conf, switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: cIncludes.add processPath(conf, arg, info)
   of "clibdir":
-    expectArg(switch, arg, pass, info)
-    if pass in {passCmd2, passPP}: cLibs.add arg.processPath(info)
+    expectArg(conf, switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: cLibs.add processPath(conf, arg, info)
   of "clib":
-    expectArg(switch, arg, pass, info)
-    if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath(info)
+    expectArg(conf, switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: cLinkedLibs.add processPath(conf, arg, info)
   of "header":
-    if config != nil: config.headerFile = arg
-    incl(gGlobalOptions, optGenIndex)
+    if conf != nil: conf.headerFile = arg
+    incl(conf.globalOptions, optGenIndex)
   of "index":
-    processOnOffSwitchG({optGenIndex}, arg, pass, info)
+    processOnOffSwitchG(conf, {optGenIndex}, arg, pass, info)
   of "import":
-    expectArg(switch, arg, pass, info)
-    if pass in {passCmd2, passPP}: implicitImports.add arg
+    expectArg(conf, switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: conf.implicitImports.add arg
   of "include":
-    expectArg(switch, arg, pass, info)
-    if pass in {passCmd2, passPP}: implicitIncludes.add arg
+    expectArg(conf, switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: conf.implicitIncludes.add arg
   of "listcmd":
-    expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optListCmd)
+    expectNoArg(conf, switch, arg, pass, info)
+    incl(conf.globalOptions, optListCmd)
   of "genmapping":
-    expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optGenMapping)
+    expectNoArg(conf, switch, arg, pass, info)
+    incl(conf.globalOptions, optGenMapping)
   of "os":
-    expectArg(switch, arg, pass, info)
+    expectArg(conf, switch, arg, pass, info)
     if pass in {passCmd1, passPP}:
       theOS = platform.nameToOS(arg)
-      if theOS == osNone: localError(info, errUnknownOS, arg)
+      if theOS == osNone: localError(conf, info, "unknown OS: '$1'" % arg)
       elif theOS != platform.hostOS:
         setTarget(theOS, targetCPU)
   of "cpu":
-    expectArg(switch, arg, pass, info)
+    expectArg(conf, switch, arg, pass, info)
     if pass in {passCmd1, passPP}:
       cpu = platform.nameToCPU(arg)
-      if cpu == cpuNone: localError(info, errUnknownCPU, arg)
+      if cpu == cpuNone: localError(conf, info, "unknown CPU: '$1'" % arg)
       elif cpu != platform.hostCPU:
         setTarget(targetOS, cpu)
   of "run", "r":
-    expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optRun)
+    expectNoArg(conf, switch, arg, pass, info)
+    incl(conf.globalOptions, optRun)
   of "verbosity":
-    expectArg(switch, arg, pass, info)
-    gVerbosity = parseInt(arg)
-    gNotes = NotesVerbosity[gVerbosity]
-    incl(gNotes, enableNotes)
-    excl(gNotes, disableNotes)
-    gMainPackageNotes = gNotes
+    expectArg(conf, switch, arg, pass, info)
+    conf.verbosity = parseInt(arg)
+    conf.notes = NotesVerbosity[conf.verbosity]
+    incl(conf.notes, conf.enableNotes)
+    excl(conf.notes, conf.disableNotes)
+    conf.mainPackageNotes = conf.notes
   of "parallelbuild":
-    expectArg(switch, arg, pass, info)
-    gNumberOfProcessors = parseInt(arg)
+    expectArg(conf, switch, arg, pass, info)
+    conf.numberOfProcessors = parseInt(arg)
   of "version", "v":
-    expectNoArg(switch, arg, pass, info)
-    writeVersionInfo(pass)
+    expectNoArg(conf, switch, arg, pass, info)
+    writeVersionInfo(conf, pass)
   of "advanced":
-    expectNoArg(switch, arg, pass, info)
-    writeAdvancedUsage(pass)
+    expectNoArg(conf, switch, arg, pass, info)
+    writeAdvancedUsage(conf, pass)
   of "fullhelp":
-    expectNoArg(switch, arg, pass, info)
-    writeFullhelp(pass)
+    expectNoArg(conf, switch, arg, pass, info)
+    writeFullhelp(conf, pass)
   of "help", "h":
-    expectNoArg(switch, arg, pass, info)
-    helpOnError(pass)
+    expectNoArg(conf, switch, arg, pass, info)
+    helpOnError(conf, pass)
   of "symbolfiles":
     case arg.normalize
-    of "on": gSymbolFiles = enabledSf
-    of "off": gSymbolFiles = disabledSf
-    of "writeonly": gSymbolFiles = writeOnlySf
-    of "readonly": gSymbolFiles = readOnlySf
-    of "v2": gSymbolFiles = v2Sf
-    else: localError(info, errOnOrOffExpectedButXFound, arg)
+    of "on": conf.symbolFiles = enabledSf
+    of "off": conf.symbolFiles = disabledSf
+    of "writeonly": conf.symbolFiles = writeOnlySf
+    of "readonly": conf.symbolFiles = readOnlySf
+    of "v2": conf.symbolFiles = v2Sf
+    else: localError(conf, info, "invalid option for --symbolFiles: " & arg)
   of "skipcfg":
-    expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optSkipConfigFile)
+    expectNoArg(conf, switch, arg, pass, info)
+    incl(conf.globalOptions, optSkipConfigFile)
   of "skipprojcfg":
-    expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optSkipProjConfigFile)
+    expectNoArg(conf, switch, arg, pass, info)
+    incl(conf.globalOptions, optSkipProjConfigFile)
   of "skipusercfg":
-    expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optSkipUserConfigFile)
+    expectNoArg(conf, switch, arg, pass, info)
+    incl(conf.globalOptions, optSkipUserConfigFile)
   of "skipparentcfg":
-    expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optSkipParentConfigFiles)
+    expectNoArg(conf, switch, arg, pass, info)
+    incl(conf.globalOptions, optSkipParentConfigFiles)
   of "genscript", "gendeps":
-    expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optGenScript)
-    incl(gGlobalOptions, optCompileOnly)
-  of "colors": processOnOffSwitchG({optUseColors}, arg, pass, info)
+    expectNoArg(conf, switch, arg, pass, info)
+    incl(conf.globalOptions, optGenScript)
+    incl(conf.globalOptions, optCompileOnly)
+  of "colors": processOnOffSwitchG(conf, {optUseColors}, arg, pass, info)
   of "lib":
-    expectArg(switch, arg, pass, info)
-    libpath = processPath(arg, info, notRelativeToProj=true)
+    expectArg(conf, switch, arg, pass, info)
+    conf.libpath = processPath(conf, arg, info, notRelativeToProj=true)
   of "putenv":
-    expectArg(switch, arg, pass, info)
-    splitSwitch(arg, key, val, pass, info)
+    expectArg(conf, switch, arg, pass, info)
+    splitSwitch(conf, arg, key, val, pass, info)
     os.putEnv(key, val)
   of "cc":
-    expectArg(switch, arg, pass, info)
-    setCC(arg)
+    expectArg(conf, switch, arg, pass, info)
+    setCC(conf, arg, info)
   of "track":
-    expectArg(switch, arg, pass, info)
-    track(arg, info)
+    expectArg(conf, switch, arg, pass, info)
+    track(conf, arg, info)
   of "trackdirty":
-    expectArg(switch, arg, pass, info)
-    trackDirty(arg, info)
+    expectArg(conf, switch, arg, pass, info)
+    trackDirty(conf, arg, info)
   of "suggest":
-    expectNoArg(switch, arg, pass, info)
-    gIdeCmd = ideSug
+    expectNoArg(conf, switch, arg, pass, info)
+    conf.ideCmd = ideSug
   of "def":
-    expectNoArg(switch, arg, pass, info)
-    gIdeCmd = ideDef
+    expectNoArg(conf, switch, arg, pass, info)
+    conf.ideCmd = ideDef
   of "eval":
-    expectArg(switch, arg, pass, info)
-    gEvalExpr = arg
+    expectArg(conf, switch, arg, pass, info)
+    conf.evalExpr = arg
   of "context":
-    expectNoArg(switch, arg, pass, info)
-    gIdeCmd = ideCon
+    expectNoArg(conf, switch, arg, pass, info)
+    conf.ideCmd = ideCon
   of "usages":
-    expectNoArg(switch, arg, pass, info)
-    gIdeCmd = ideUse
+    expectNoArg(conf, switch, arg, pass, info)
+    conf.ideCmd = ideUse
   of "stdout":
-    expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optStdout)
+    expectNoArg(conf, switch, arg, pass, info)
+    incl(conf.globalOptions, optStdout)
   of "listfullpaths":
-    expectNoArg(switch, arg, pass, info)
-    gListFullPaths = true
+    expectNoArg(conf, switch, arg, pass, info)
+    incl conf.globalOptions, optListFullPaths
   of "dynliboverride":
-    dynlibOverride(switch, arg, pass, info)
+    dynlibOverride(conf, switch, arg, pass, info)
   of "dynliboverrideall":
-    expectNoArg(switch, arg, pass, info)
-    gDynlibOverrideAll = true
+    expectNoArg(conf, switch, arg, pass, info)
+    incl conf.globalOptions, optDynlibOverrideAll
   of "cs":
     # only supported for compatibility. Does nothing.
-    expectArg(switch, arg, pass, info)
+    expectArg(conf, switch, arg, pass, info)
   of "experimental":
     if arg.len == 0:
-      config.features.incl oldExperimentalFeatures
+      conf.features.incl oldExperimentalFeatures
     else:
       try:
-        config.features.incl parseEnum[Feature](arg)
+        conf.features.incl parseEnum[Feature](arg)
       except ValueError:
-        localError(info, "unknown experimental feature")
+        localError(conf, info, "unknown experimental feature")
   of "nocppexceptions":
-    expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optNoCppExceptions)
-    defineSymbol("noCppExceptions")
+    expectNoArg(conf, switch, arg, pass, info)
+    incl(conf.globalOptions, optNoCppExceptions)
+    defineSymbol(conf.symbols, "noCppExceptions")
   of "cppdefine":
-    expectArg(switch, arg, pass, info)
-    if config != nil:
-      config.cppDefine(arg)
+    expectArg(conf, switch, arg, pass, info)
+    if conf != nil:
+      conf.cppDefine(arg)
   of "newruntime":
-    expectNoArg(switch, arg, pass, info)
-    doAssert(config != nil)
-    incl(config.features, destructor)
-    defineSymbol("nimNewRuntime")
+    expectNoArg(conf, switch, arg, pass, info)
+    doAssert(conf != nil)
+    incl(conf.features, destructor)
+    defineSymbol(conf.symbols, "nimNewRuntime")
   of "cppcompiletonamespace":
-    expectNoArg(switch, arg, pass, info)
-    useNimNamespace = true
-    defineSymbol("cppCompileToNamespace")
+    expectNoArg(conf, switch, arg, pass, info)
+    incl conf.globalOptions, optUseNimNamespace
+    defineSymbol(conf.symbols, "cppCompileToNamespace")
   else:
-    if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
-    else: invalidCmdLineOption(pass, switch, info)
+    if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg)
+    else: invalidCmdLineOption(conf, pass, switch, info)
+
+template gCmdLineInfo*(): untyped = newLineInfo(config, "command line", 1, 1)
 
-proc processCommand(switch: string, pass: TCmdLinePass; config: ConfigRef) =
+proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) =
   var cmd, arg: string
-  splitSwitch(switch, cmd, arg, pass, gCmdLineInfo)
+  splitSwitch(config, switch, cmd, arg, pass, gCmdLineInfo)
   processSwitch(cmd, arg, pass, gCmdLineInfo, config)
 
 
@@ -755,17 +751,17 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser;
   if argsCount == 0:
     # nim filename.nims  is the same as "nim e filename.nims":
     if p.key.endswith(".nims"):
-      options.command = "e"
-      options.gProjectName = unixToNativePath(p.key)
+      config.command = "e"
+      config.projectName = unixToNativePath(p.key)
       config.arguments = cmdLineRest(p)
       result = true
     elif pass != passCmd2:
-      options.command = p.key
+      config.command = p.key
   else:
-    if pass == passCmd1: options.commandArgs.add p.key
+    if pass == passCmd1: config.commandArgs.add p.key
     if argsCount == 1:
       # support UNIX style filenames everywhere for portable build scripts:
-      options.gProjectName = unixToNativePath(p.key)
+      config.projectName = unixToNativePath(p.key)
       config.arguments = cmdLineRest(p)
       result = true
   inc argsCount
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index f8a75e68e..773c0faf9 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -12,77 +12,30 @@
 import
   strtabs, platform, strutils, idents
 
-# We need to use a StringTableRef here as defined symbols are always guaranteed
-# to be style insensitive. Otherwise hell would break lose.
-var gSymbols: StringTableRef
-
 const
   catNone = "false"
 
-proc defineSymbol*(symbol: string, value: string = "true") =
-  gSymbols[symbol] = value
-
-proc undefSymbol*(symbol: string) =
-  gSymbols[symbol] = catNone
-
-proc isDefined*(symbol: string): bool =
-  if gSymbols.hasKey(symbol):
-    result = gSymbols[symbol] != catNone
-  elif cmpIgnoreStyle(symbol, CPU[targetCPU].name) == 0:
-    result = true
-  elif cmpIgnoreStyle(symbol, platform.OS[targetOS].name) == 0:
-    result = true
-  else:
-    case symbol.normalize
-    of "x86": result = targetCPU == cpuI386
-    of "itanium": result = targetCPU == cpuIa64
-    of "x8664": result = targetCPU == cpuAmd64
-    of "posix", "unix":
-      result = targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos,
-                            osQnx, osAtari, osAix,
-                            osHaiku, osVxWorks, osSolaris, osNetbsd,
-                            osFreebsd, osOpenbsd, osDragonfly, osMacosx,
-                            osAndroid}
-    of "linux":
-      result = targetOS in {osLinux, osAndroid}
-    of "bsd":
-      result = targetOS in {osNetbsd, osFreebsd, osOpenbsd, osDragonfly}
-    of "emulatedthreadvars":
-      result = platform.OS[targetOS].props.contains(ospLacksThreadVars)
-    of "msdos": result = targetOS == osDos
-    of "mswindows", "win32": result = targetOS == osWindows
-    of "macintosh": result = targetOS in {osMacos, osMacosx}
-    of "sunos": result = targetOS == osSolaris
-    of "littleendian": result = CPU[targetCPU].endian == platform.littleEndian
-    of "bigendian": result = CPU[targetCPU].endian == platform.bigEndian
-    of "cpu8": result = CPU[targetCPU].bit == 8
-    of "cpu16": result = CPU[targetCPU].bit == 16
-    of "cpu32": result = CPU[targetCPU].bit == 32
-    of "cpu64": result = CPU[targetCPU].bit == 64
-    of "nimrawsetjmp":
-      result = targetOS in {osSolaris, osNetbsd, osFreebsd, osOpenbsd,
-                            osDragonfly, osMacosx}
-    else: discard
-
-proc isDefined*(symbol: PIdent): bool = isDefined(symbol.s)
+proc defineSymbol*(symbols: StringTableRef; symbol: string, value: string = "true") =
+  symbols[symbol] = value
 
-proc lookupSymbol*(symbol: string): string =
-  result = if isDefined(symbol): gSymbols[symbol] else: nil
+proc undefSymbol*(symbols: StringTableRef; symbol: string) =
+  symbols[symbol] = catNone
 
-proc lookupSymbol*(symbol: PIdent): string = lookupSymbol(symbol.s)
+#proc lookupSymbol*(symbols: StringTableRef; symbol: string): string =
+#  result = if isDefined(symbol): gSymbols[symbol] else: nil
 
-iterator definedSymbolNames*: string =
-  for key, val in pairs(gSymbols):
+iterator definedSymbolNames*(symbols: StringTableRef): string =
+  for key, val in pairs(symbols):
     if val != catNone: yield key
 
-proc countDefinedSymbols*(): int =
+proc countDefinedSymbols*(symbols: StringTableRef): int =
   result = 0
-  for key, val in pairs(gSymbols):
+  for key, val in pairs(symbols):
     if val != catNone: inc(result)
 
-proc initDefines*() =
-  gSymbols = newStringTable(modeStyleInsensitive)
+proc initDefines*(symbols: StringTableRef) =
   # for bootstrapping purposes and old code:
+  template defineSymbol(s) = symbols.defineSymbol(s)
   defineSymbol("nimhygiene")
   defineSymbol("niminheritable")
   defineSymbol("nimmixin")
diff --git a/compiler/configuration.nim b/compiler/configuration.nim
new file mode 100644
index 000000000..f9f0e623c
--- /dev/null
+++ b/compiler/configuration.nim
@@ -0,0 +1,360 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2018 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains the rather excessive configuration object that
+## needs to be passed around to everything so that the compiler becomes
+## more useful as a library.
+
+import tables
+
+const
+  explanationsBaseUrl* = "https://nim-lang.org/docs/manual"
+
+type
+  TMsgKind* = enum
+    errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile,
+    errXExpected,
+    errGridTableNotImplemented,
+    errGeneralParseError,
+    errNewSectionExpected,
+    errInvalidDirectiveX,
+    errGenerated,
+    errUser,
+    warnCannotOpenFile,
+    warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
+    warnDeprecated, warnConfigDeprecated,
+    warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
+    warnUnknownSubstitutionX, warnLanguageXNotSupported,
+    warnFieldXNotSupported, warnCommentXIgnored,
+    warnTypelessParam,
+    warnUseBase, warnWriteToForeignHeap, warnUnsafeCode,
+    warnEachIdentIsTuple, warnShadowIdent,
+    warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
+    warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
+    warnInconsistentSpacing, warnUser,
+    hintSuccess, hintSuccessX,
+    hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
+    hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
+    hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
+    hintConditionAlwaysTrue, hintName, hintPattern,
+    hintExecuting, hintLinking, hintDependency,
+    hintSource, hintPerformance, hintStackTrace, hintGCStats,
+    hintUser, hintUserRaw
+
+const
+  MsgKindToStr*: array[TMsgKind, string] = [
+    errUnknown: "unknown error",
+    errInternal: "internal error: $1",
+    errIllFormedAstX: "illformed AST: $1",
+    errCannotOpenFile: "cannot open '$1'",
+    errXExpected: "'$1' expected",
+    errGridTableNotImplemented: "grid table is not implemented",
+    errGeneralParseError: "general parse error",
+    errNewSectionExpected: "new section expected",
+    errInvalidDirectiveX: "invalid directive: '$1'",
+    errGenerated: "$1",
+    errUser: "$1",
+    warnCannotOpenFile: "cannot open '$1'",
+    warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
+    warnXIsNeverRead: "'$1' is never read",
+    warnXmightNotBeenInit: "'$1' might not have been initialized",
+    warnDeprecated: "$1 is deprecated",
+    warnConfigDeprecated: "config file '$1' is deprecated",
+    warnSmallLshouldNotBeUsed: "'l' should not be used as an identifier; may look like '1' (one)",
+    warnUnknownMagic: "unknown magic '$1' might crash the compiler",
+    warnRedefinitionOfLabel: "redefinition of label '$1'",
+    warnUnknownSubstitutionX: "unknown substitution '$1'",
+    warnLanguageXNotSupported: "language '$1' not supported",
+    warnFieldXNotSupported: "field '$1' not supported",
+    warnCommentXIgnored: "comment '$1' ignored",
+    warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'",
+    warnUseBase: "use {.base.} for base methods; baseless methods are deprecated",
+    warnWriteToForeignHeap: "write to foreign heap",
+    warnUnsafeCode: "unsafe code: '$1'",
+    warnEachIdentIsTuple: "each identifier is a tuple",
+    warnShadowIdent: "shadowed identifier: '$1'",
+    warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future.",
+    warnProveField: "cannot prove that field '$1' is accessible",
+    warnProveIndex: "cannot prove index '$1' is valid",
+    warnGcUnsafe: "not GC-safe: '$1'",
+    warnGcUnsafe2: "$1",
+    warnUninit: "'$1' might not have been initialized",
+    warnGcMem: "'$1' uses GC'ed memory",
+    warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.",
+    warnLockLevel: "$1",
+    warnResultShadowed: "Special variable 'result' is shadowed.",
+    warnInconsistentSpacing: "Number of spaces around '$#' is not consistent",
+    warnUser: "$1",
+    hintSuccess: "operation successful",
+    hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)",
+    hintLineTooLong: "line too long",
+    hintXDeclaredButNotUsed: "'$1' is declared but not used",
+    hintConvToBaseNotNeeded: "conversion to base object is not needed",
+    hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless",
+    hintExprAlwaysX: "expression evaluates always to '$1'",
+    hintQuitCalled: "quit() called",
+    hintProcessing: "$1",
+    hintCodeBegin: "generated code listing:",
+    hintCodeEnd: "end of listing",
+    hintConf: "used config file '$1'",
+    hintPath: "added path: '$1'",
+    hintConditionAlwaysTrue: "condition is always true: '$1'",
+    hintName: "name should be: '$1'",
+    hintPattern: "$1",
+    hintExecuting: "$1",
+    hintLinking: "",
+    hintDependency: "$1",
+    hintSource: "$1",
+    hintPerformance: "$1",
+    hintStackTrace: "$1",
+    hintGCStats: "$1",
+    hintUser: "$1",
+    hintUserRaw: "$1"]
+
+const
+  WarningsToStr* = ["CannotOpenFile", "OctalEscape",
+    "XIsNeverRead", "XmightNotBeenInit",
+    "Deprecated", "ConfigDeprecated",
+    "SmallLshouldNotBeUsed", "UnknownMagic",
+    "RedefinitionOfLabel", "UnknownSubstitutionX",
+    "LanguageXNotSupported", "FieldXNotSupported",
+    "CommentXIgnored",
+    "TypelessParam", "UseBase", "WriteToForeignHeap",
+    "UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
+    "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
+    "GcMem", "Destructor", "LockLevel", "ResultShadowed",
+    "Spacing", "User"]
+
+  HintsToStr* = ["Success", "SuccessX", "LineTooLong",
+    "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
+    "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
+    "Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency",
+    "Source", "Performance", "StackTrace", "GCStats",
+    "User", "UserRaw"]
+
+const
+  fatalMin* = errUnknown
+  fatalMax* = errInternal
+  errMin* = errUnknown
+  errMax* = errUser
+  warnMin* = warnCannotOpenFile
+  warnMax* = pred(hintSuccess)
+  hintMin* = hintSuccess
+  hintMax* = high(TMsgKind)
+
+static:
+  doAssert HintsToStr.len == ord(hintMax) - ord(hintMin) + 1
+  doAssert WarningsToStr.len == ord(warnMax) - ord(warnMin) + 1
+
+type
+  TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
+  TNoteKinds* = set[TNoteKind]
+
+const
+  NotesVerbosity*: array[0..3, TNoteKinds] = [
+    {low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
+                                         warnProveField, warnProveIndex,
+                                         warnGcUnsafe,
+                                         hintSuccessX, hintPath, hintConf,
+                                         hintProcessing, hintPattern,
+                                         hintDependency,
+                                         hintExecuting, hintLinking,
+                                         hintCodeBegin, hintCodeEnd,
+                                         hintSource, hintStackTrace,
+                                         hintGCStats},
+    {low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
+                                         warnProveField, warnProveIndex,
+                                         warnGcUnsafe,
+                                         hintPath,
+                                         hintDependency,
+                                         hintCodeBegin, hintCodeEnd,
+                                         hintSource, hintStackTrace,
+                                         hintGCStats},
+    {low(TNoteKind)..high(TNoteKind)} - {hintStackTrace, warnUninit},
+    {low(TNoteKind)..high(TNoteKind)}]
+
+const
+  errXMustBeCompileTime* = "'$1' can only be used in compile-time context"
+  errArgsNeedRunOption* = "arguments can only be given if the '--run' option is selected"
+
+#[
+errStringLiteralExpected: "string literal expected",
+errIntLiteralExpected: "integer literal expected",
+errIdentifierExpected: "identifier expected, but found '$1'",
+errNewlineExpected: "newline expected, but found '$1'",
+errInvalidModuleName: "invalid module name: '$1'",
+errOnOrOffExpected: "'on' or 'off' expected",
+errNoneSpeedOrSizeExpected: "'none', 'speed' or 'size' expected",
+errInvalidPragma: "invalid pragma",
+errUnknownPragma: "unknown pragma: '$1'",
+errAtPopWithoutPush: "'pop' without a 'push' pragma",
+errEmptyAsm: "empty asm statement",
+errInvalidIndentation: "invalid indentation",
+
+errNoReturnWithReturnTypeNotAllowed: "routines with NoReturn pragma are not allowed to have return type",
+errAttemptToRedefine: ,
+errStmtInvalidAfterReturn: "statement not allowed after 'return', 'break', 'raise', 'continue' or proc call with noreturn pragma",
+errStmtExpected: "statement expected",
+errInvalidLabel: "'$1' is no label",
+errInvalidCmdLineOption: "invalid command line option: '$1'",
+errCmdLineArgExpected: "argument for command line option expected: '$1'",
+errCmdLineNoArgExpected: "invalid argument for command line option: '$1'",
+errInvalidVarSubstitution: "invalid variable substitution in '$1'",
+errUnknownVar: "unknown variable: '$1'",
+errUnknownCcompiler: "unknown C compiler: '$1'",
+errOnOrOffExpectedButXFound: "'on' or 'off' expected, but '$1' found",
+errOnOffOrListExpectedButXFound: "'on', 'off' or 'list' expected, but '$1' found",
+errGenOutExpectedButXFound: "'c', 'c++' or 'yaml' expected, but '$1' found",
+,
+errInvalidMultipleAsgn: "multiple assignment is not allowed",
+errColonOrEqualsExpected: "':' or '=' expected, but found '$1'",
+errUndeclaredField: "undeclared field: '$1'",
+errUndeclaredRoutine: "attempting to call undeclared routine: '$1'",
+errUseQualifier: "ambiguous identifier: '$1' -- use a qualifier",
+errTypeExpected: "type expected",
+errSystemNeeds: "system module needs '$1'",
+errExecutionOfProgramFailed: "execution of an external program failed: '$1'",
+errNotOverloadable: ,
+errInvalidArgForX: "invalid argument for '$1'",
+errStmtHasNoEffect: "statement has no effect",
+,
+errXExpectsArrayType: "'$1' expects an array type",
+errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet",
+errExprXAmbiguous: "expression '$1' ambiguous in this context",
+errConstantDivisionByZero: ,
+errOrdinalOrFloatTypeExpected: "ordinal or float type expected",
+errOverOrUnderflow: ,
+errCannotEvalXBecauseIncompletelyDefined: ,
+errChrExpectsRange0_255: "'chr' expects an int in the range 0..255",
+errDynlibRequiresExportc: "'dynlib' requires 'exportc'",
+errNilAccess: "attempt to access a nil address",
+errIndexOutOfBounds: "index out of bounds",
+errIndexTypesDoNotMatch: "index types do not match",
+errBracketsInvalidForType: "'[]' operator invalid for this type",
+errValueOutOfSetBounds: "value out of set bounds",
+errFieldNotInit: "field '$1' not initialized",
+errExprXCannotBeCalled: "expression '$1' cannot be called",
+errExprHasNoType: "expression has no type",
+errExprXHasNoType:,
+errCastNotInSafeMode: "'cast' not allowed in safe mode",
+errExprCannotBeCastToX: ,
+errCommaOrParRiExpected: "',' or ')' expected",
+errCurlyLeOrParLeExpected: "'{' or '(' expected",
+errSectionExpected: "section ('type', 'proc', etc.) expected",
+errRangeExpected: "range expected",
+errMagicOnlyInSystem: "'magic' only allowed in system module",
+errPowerOfTwoExpected: "power of two expected",
+errStringMayNotBeEmpty: "string literal may not be empty",
+errCallConvExpected: "calling convention expected",
+errProcOnlyOneCallConv: "a proc can only have one calling convention",
+errSymbolMustBeImported: "symbol must be imported if 'lib' pragma is used",
+errExprMustBeBool: "expression must be of type 'bool'",
+errConstExprExpected: "constant expression expected",
+errDuplicateCaseLabel: "duplicate case label",
+errRangeIsEmpty: "range is empty",
+,
+errSelectorMustBeOrdinal: "selector must be of an ordinal type",
+errOrdXMustNotBeNegative: "ord($1) must not be negative",
+errLenXinvalid: "len($1) must be less than 32768",
+errTypeXhasUnknownSize: "type '$1' has unknown size",
+errConstNeedsConstExpr: "a constant can only be initialized with a constant expression",
+errConstNeedsValue: "a constant needs a value",
+errResultCannotBeOpenArray: "the result type cannot be on open array",
+errSizeTooBig: "computing the type's size produced an overflow",
+errInheritanceOnlyWithEnums: "inheritance only works with an enum",
+errIllegalRecursionInTypeX:,
+errCannotInstantiateX: "cannot instantiate: '$1'",
+errTypeMismatch: "type mismatch: got <",
+errButExpected: "but expected one of: ",
+errButExpectedX: "but expected '$1'",
+errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3",
+errWrongNumberOfArguments: "wrong number of arguments",
+errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'",
+errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters",
+errXCannotBePassedToProcVar: ,
+,
+errImplOfXexpected: ,
+
+errIllegalConvFromXtoY: ,
+errCannotBindXTwice: "cannot bind parameter '$1' twice",
+errInvalidOrderInArrayConstructor: ,
+errInvalidOrderInEnumX: "invalid order in enum '$1'",
+errEnumXHasHoles: "enum '$1' has holes",
+errExceptExpected: "'except' or 'finally' expected",
+errInvalidTry: "after catch all 'except' or 'finally' no section may follow",
+errOptionExpected: ,
+errXisNoLabel: "'$1' is not a label",
+errNotAllCasesCovered: "not all cases are covered",
+errUnknownSubstitionVar: "unknown substitution variable: '$1'",
+errComplexStmtRequiresInd: "complex statement requires indentation",
+errXisNotCallable: "'$1' is not callable",
+errNoPragmasAllowedForX: "no pragmas allowed for $1",
+,
+errInvalidParamKindX: "invalid param kind: '$1'",
+errDefaultArgumentInvalid: "default argument invalid",
+errNamedParamHasToBeIdent: "named parameter has to be an identifier",
+errNoReturnTypeForX: "no return type allowed for $1",
+errConvNeedsOneArg: "a type conversion needs exactly one argument",
+errInvalidPragmaX: ,
+errXNotAllowedHere: "$1 not allowed here",
+errXisNoType: "invalid type: '$1'",
+errCircumNeedsPointer: "'[]' needs a pointer or reference type",
+errInvalidExpression: "invalid expression",
+errInvalidExpressionX: "invalid expression: '$1'",
+errEnumHasNoValueX: "enum has no value '$1'",
+,
+errNoCommand: "no command given",
+errInvalidCommandX: "invalid command: '$1'",
+errXNeedsParamObjectType: ,
+errTemplateInstantiationTooNested: "template instantiation too nested, try --evalTemplateLimit:N",
+errMacroInstantiationTooNested: "macro instantiation too nested, try --evalMacroLimit:N",
+errInstantiationFrom: "template/generic instantiation from here",
+errInvalidIndexValueForTuple: "invalid index value for tuple subscript",
+errCommandExpectsFilename: "command expects a filename argument",
+errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file",
+errXExpected: "'$1' expected",
+,
+errCastToANonConcreteType: "cannot cast to a non concrete type: '$1'",
+errInvalidSectionStart: "invalid section start",
+errGridTableNotImplemented: "grid table is not implemented",
+errGeneralParseError: "general parse error",
+errNewSectionExpected: "new section expected",
+errWhitespaceExpected: "whitespace expected, got '$1'",
+errXisNoValidIndexFile: "'$1' is no valid index file",
+errCannotRenderX: "cannot render reStructuredText element '$1'",
+errVarVarTypeNotAllowed: ,
+errInstantiateXExplicitly: "instantiate '$1' explicitly",
+errOnlyACallOpCanBeDelegator: ,
+errUsingNoSymbol: "'$1' is not a variable, constant or a proc name",
+errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " &
+                                   "because the parameter '$1' has a generic type",
+errDestructorNotGenericEnough: "Destructor signature is too specific. " &
+                               "A destructor must be associated will all instantiations of a generic type",
+errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " &
+                                "templates, macros and other inline iterators",
+errXExpectsTwoArguments: "'$1' expects two arguments",
+errXExpectsObjectTypes: "'$1' expects object types",
+errXcanNeverBeOfThisSubtype: "'$1' can never be of this subtype",
+errTooManyIterations: "interpretation requires too many iterations; " &
+  "if you are sure this is not a bug in your code edit " &
+  "compiler/vmdef.MaxLoopIterations and rebuild the compiler",
+errFieldXNotFound: "field '$1' cannot be found",
+errInvalidConversionFromTypeX: "invalid conversion from type '$1'",
+errAssertionFailed: "assertion failed",
+errCannotGenerateCodeForX: "cannot generate code for '$1'",
+errXRequiresOneArgument: "$1 requires one parameter",
+errUnhandledExceptionX: "unhandled exception: $1",
+errCyclicTree: "macro returned a cyclic abstract syntax tree",
+errXisNoMacroOrTemplate: "'$1' is no macro or template",
+errXhasSideEffects: "'$1' can have side effects",
+errWrongSymbolX:,
+errIllegalCaptureX: "illegal capture '$1'",
+errXCannotBeClosure: "'$1' cannot have 'closure' calling convention",
+,
+]#
diff --git a/compiler/depends.nim b/compiler/depends.nim
index 2b600c1da..732404232 100644
--- a/compiler/depends.nim
+++ b/compiler/depends.nim
@@ -19,6 +19,7 @@ proc generateDot*(project: string)
 type
   TGen = object of TPassContext
     module*: PSym
+    config: ConfigRef
   PGen = ref TGen
 
 var gDotGraph: Rope # the generated DOT file; we need a global variable
@@ -33,10 +34,10 @@ proc addDotDependency(c: PPassContext, n: PNode): PNode =
   case n.kind
   of nkImportStmt:
     for i in countup(0, sonsLen(n) - 1):
-      var imported = getModuleName(n.sons[i])
+      var imported = getModuleName(g.config, n.sons[i])
       addDependencyAux(g.module.name.s, imported)
   of nkFromStmt, nkImportExceptStmt:
-    var imported = getModuleName(n.sons[0])
+    var imported = getModuleName(g.config, n.sons[0])
     addDependencyAux(g.module.name.s, imported)
   of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
     for i in countup(0, sonsLen(n) - 1): discard addDotDependency(c, n.sons[i])
@@ -52,6 +53,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
   var g: PGen
   new(g)
   g.module = module
+  g.config = graph.config
   result = g
 
 const gendependPass* = makePass(open = myOpen, process = addDotDependency)
diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim
index cd16469de..31c735794 100644
--- a/compiler/destroyer.nim
+++ b/compiler/destroyer.nim
@@ -116,7 +116,8 @@ Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently
 
 import
   intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
-  strutils, options, dfa, lowerings, rodread, tables
+  strutils, options, dfa, lowerings, rodread, tables, modulegraphs,
+  configuration
 
 const
   InterestingSyms = {skVar, skResult, skLet}
@@ -130,6 +131,7 @@ type
     tmp: PSym
     destroys, topLevelVars: PNode
     toDropBit: Table[int, PSym]
+    graph: ModuleGraph
 
 proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode =
   # XXX why are temps fields in an object here?
@@ -222,21 +224,21 @@ proc patchHead(s: PSym) =
 template genOp(opr, opname) =
   let op = opr
   if op == nil:
-    globalError(dest.info, "internal error: '" & opname & "' operator not found for type " & typeToString(t))
+    globalError(c.graph.config, dest.info, "internal error: '" & opname & "' operator not found for type " & typeToString(t))
   elif op.ast[genericParamsPos].kind != nkEmpty:
-    globalError(dest.info, "internal error: '" & opname & "' operator is generic")
+    globalError(c.graph.config, dest.info, "internal error: '" & opname & "' operator is generic")
   patchHead op
   result = newTree(nkCall, newSymNode(op), newTree(nkHiddenAddr, dest))
 
-proc genSink(t: PType; dest: PNode): PNode =
+proc genSink(c: Con; t: PType; dest: PNode): PNode =
   let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
   genOp(if t.sink != nil: t.sink else: t.assignment, "=sink")
 
-proc genCopy(t: PType; dest: PNode): PNode =
+proc genCopy(c: Con; t: PType; dest: PNode): PNode =
   let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
   genOp(t.assignment, "=")
 
-proc genDestroy(t: PType; dest: PNode): PNode =
+proc genDestroy(c: Con; t: PType; dest: PNode): PNode =
   let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
   genOp(t.destructor, "=destroy")
 
@@ -249,14 +251,14 @@ proc dropBit(c: var Con; s: PSym): PSym =
 
 proc registerDropBit(c: var Con; s: PSym) =
   let result = newSym(skTemp, getIdent(s.name.s & "_AliveBit"), c.owner, s.info)
-  result.typ = getSysType(tyBool)
+  result.typ = getSysType(c.graph, s.info, tyBool)
   let trueVal = newIntTypeNode(nkIntLit, 1, result.typ)
   c.topLevelVars.add newTree(nkIdentDefs, newSymNode result, emptyNode, trueVal)
   c.toDropBit[s.id] = result
   # generate:
   #  if not sinkParam_AliveBit: `=destroy`(sinkParam)
   c.destroys.add newTree(nkIfStmt,
-    newTree(nkElifBranch, newSymNode result, genDestroy(s.typ, newSymNode s)))
+    newTree(nkElifBranch, newSymNode result, genDestroy(c, s.typ, newSymNode s)))
 
 proc p(n: PNode; c: var Con): PNode
 
@@ -274,36 +276,36 @@ proc destructiveMoveSink(n: PNode; c: var Con): PNode =
   result = newNodeIT(nkStmtListExpr, n.info, n.typ)
   let bit = newSymNode dropBit(c, n.sym)
   if optMoveCheck in c.owner.options:
-    result.add callCodegenProc("chckMove", bit)
+    result.add callCodegenProc(c.graph, "chckMove", bit)
   result.add newTree(nkAsgn, bit,
-    newIntTypeNode(nkIntLit, 0, getSysType(tyBool)))
+    newIntTypeNode(nkIntLit, 0, getSysType(c.graph, n.info, tyBool)))
   result.add n
 
 proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
   if ri.kind in constrExprs:
-    result = genSink(ri.typ, dest)
+    result = genSink(c, ri.typ, dest)
     # watch out and no not transform 'ri' twice if it's a call:
     let ri2 = copyNode(ri)
     recurse(ri, ri2)
     result.add ri2
   elif ri.kind == nkSym and isHarmlessVar(ri.sym, c):
-    result = genSink(ri.typ, dest)
+    result = genSink(c, ri.typ, dest)
     result.add p(ri, c)
   elif ri.kind == nkSym and isSinkParam(ri.sym):
-    result = genSink(ri.typ, dest)
+    result = genSink(c, ri.typ, dest)
     result.add destructiveMoveSink(ri, c)
   else:
-    result = genCopy(ri.typ, dest)
+    result = genCopy(c, ri.typ, dest)
     result.add p(ri, c)
 
 proc passCopyToSink(n: PNode; c: var Con): PNode =
   result = newNodeIT(nkStmtListExpr, n.info, n.typ)
   let tmp = getTemp(c, n.typ, n.info)
   if hasDestructor(n.typ):
-    var m = genCopy(n.typ, tmp)
+    var m = genCopy(c, n.typ, tmp)
     m.add p(n, c)
     result.add m
-    message(n.info, hintPerformance,
+    message(c.graph.config, n.info, hintPerformance,
       "passing '$1' to a sink parameter introduces an implicit copy; " &
       "use 'move($1)' to prevent it" % $n)
   else:
@@ -312,7 +314,7 @@ proc passCopyToSink(n: PNode; c: var Con): PNode =
 
 proc genReset(n: PNode; c: var Con): PNode =
   result = newNodeI(nkCall, n.info)
-  result.add(newSymNode(createMagic("reset", mReset)))
+  result.add(newSymNode(createMagic(c.graph, "reset", mReset)))
   # The mReset builtin does not take the address:
   result.add n
 
@@ -345,7 +347,7 @@ proc p(n: PNode; c: var Con): PNode =
       let L = it.len-1
       let ri = it[L]
       if it.kind == nkVarTuple and hasDestructor(ri.typ):
-        let x = lowerTupleUnpacking(it, c.owner)
+        let x = lowerTupleUnpacking(c.graph, it, c.owner)
         result.add p(x, c)
       elif it.kind == nkIdentDefs and hasDestructor(it[0].typ):
         for j in 0..L-2:
@@ -354,7 +356,7 @@ proc p(n: PNode; c: var Con): PNode =
           # move the variable declaration to the top of the frame:
           c.addTopVar v
           # make sure it's destroyed at the end of the proc:
-          c.destroys.add genDestroy(v.typ, v)
+          c.destroys.add genDestroy(c, v.typ, v)
           if ri.kind != nkEmpty:
             let r = moveOrCopy(v, ri, c)
             result.add r
@@ -400,11 +402,11 @@ proc p(n: PNode; c: var Con): PNode =
       discard "produce temp creation"
       result = newNodeIT(nkStmtListExpr, n.info, n.typ)
       let tmp = getTemp(c, n.typ, n.info)
-      var sinkExpr = genSink(n.typ, tmp)
+      var sinkExpr = genSink(c, n.typ, tmp)
       sinkExpr.add n
       result.add sinkExpr
       result.add tmp
-      c.destroys.add genDestroy(n.typ, tmp)
+      c.destroys.add genDestroy(c, n.typ, tmp)
     else:
       result = n
   of nkAsgn, nkFastAsgn:
@@ -420,17 +422,18 @@ proc p(n: PNode; c: var Con): PNode =
     result = copyNode(n)
     recurse(n, result)
 
-proc injectDestructorCalls*(owner: PSym; n: PNode): PNode =
+proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
   when defined(nimDebugDestroys):
     echo "injecting into ", n
   var c: Con
   c.owner = owner
   c.tmp = newSym(skTemp, getIdent":d", owner, n.info)
-  c.tmpObj = createObj(owner, n.info)
+  c.tmpObj = createObj(g, owner, n.info)
   c.tmp.typ = c.tmpObj
   c.destroys = newNodeI(nkStmtList, n.info)
   c.topLevelVars = newNodeI(nkVarSection, n.info)
   c.toDropBit = initTable[int, PSym]()
+  c.graph = g
   let cfg = constructCfg(owner, n)
   shallowCopy(c.g, cfg)
   c.jumpTargets = initIntSet()
diff --git a/compiler/dfa.nim b/compiler/dfa.nim
index bc9d13870..0fd706178 100644
--- a/compiler/dfa.nim
+++ b/compiler/dfa.nim
@@ -23,7 +23,7 @@
 ## "A Graph–Free Approach to Data–Flow Analysis" by Markus Mohnen.
 ## https://link.springer.com/content/pdf/10.1007/3-540-45937-5_6.pdf
 
-import ast, astalgo, types, intsets, tables, msgs
+import ast, astalgo, types, intsets, tables, msgs, options
 
 type
   InstrKind* = enum
@@ -102,14 +102,14 @@ proc genLabel(c: Con): TPosition =
 
 proc jmpBack(c: var Con, n: PNode, p = TPosition(0)) =
   let dist = p.int - c.code.len
-  internalAssert(-0x7fff < dist and dist < 0x7fff)
+  doAssert(-0x7fff < dist and dist < 0x7fff)
   c.code.add Instr(n: n, kind: goto, dest: dist)
 
 proc patch(c: var Con, p: TPosition) =
   # patch with current index
   let p = p.int
   let diff = c.code.len - p
-  internalAssert(-0x7fff < diff and diff < 0x7fff)
+  doAssert(-0x7fff < diff and diff < 0x7fff)
   c.code[p].dest = diff
 
 proc popBlock(c: var Con; oldLen: int) =
@@ -160,7 +160,7 @@ proc genBreak(c: var Con; n: PNode) =
       if c.blocks[i].label == n.sons[0].sym:
         c.blocks[i].fixups.add L1
         return
-    globalError(n.info, errGenerated, "VM problem: cannot find 'break' target")
+    #globalError(n.info, "VM problem: cannot find 'break' target")
   else:
     c.blocks[c.blocks.high].fixups.add L1
 
@@ -334,7 +334,7 @@ proc gen(c: var Con; n: PNode) =
   of nkVarSection, nkLetSection: genVarSection(c, n)
   else: discard
 
-proc dfa(code: seq[Instr]) =
+proc dfa(code: seq[Instr]; conf: ConfigRef) =
   var u = newSeq[IntSet](code.len) # usages
   var d = newSeq[IntSet](code.len) # defs
   var c = newSeq[IntSet](code.len) # consumed
@@ -426,17 +426,17 @@ proc dfa(code: seq[Instr]) =
     of use, useWithinCall:
       let s = code[i].sym
       if s.id notin d[i]:
-        localError(code[i].n.info, "usage of uninitialized variable: " & s.name.s)
+        localError(conf, code[i].n.info, "usage of uninitialized variable: " & s.name.s)
       if s.id in c[i]:
-        localError(code[i].n.info, "usage of an already consumed variable: " & s.name.s)
+        localError(conf, code[i].n.info, "usage of an already consumed variable: " & s.name.s)
 
     else: discard
 
-proc dataflowAnalysis*(s: PSym; body: PNode) =
+proc dataflowAnalysis*(s: PSym; body: PNode; conf: ConfigRef) =
   var c = Con(code: @[], blocks: @[])
   gen(c, body)
   when defined(useDfa) and defined(debugDfa): echoCfg(c.code)
-  dfa(c.code)
+  dfa(c.code, conf)
 
 proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph =
   ## constructs a control flow graph for ``body``.
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index e1a70a23e..7ab2f0eee 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -16,7 +16,7 @@ import
   wordrecg, syntaxes, renderer, lexer, packages/docutils/rstast,
   packages/docutils/rst, packages/docutils/rstgen, times,
   packages/docutils/highlite, sempass2, json, xmltree, cgi,
-  typesrenderer, astalgo, modulepaths
+  typesrenderer, astalgo, modulepaths, configuration
 
 type
   TSections = array[TSymKind, Rope]
@@ -29,6 +29,7 @@ type
     jArray: JsonNode
     types: TStrTable
     isPureRst: bool
+    conf*: ConfigRef
 
   PDoc* = ref TDocumentor ## Alias to type less.
 
@@ -53,42 +54,47 @@ proc attachToType(d: PDoc; p: PSym): PSym =
   if params.len > 0: check(0)
   for i in 2..<params.len: check(i)
 
-proc compilerMsgHandler(filename: string, line, col: int,
-                        msgKind: rst.MsgKind, arg: string) {.procvar.} =
-  # translate msg kind:
-  var k: msgs.TMsgKind
-  case msgKind
-  of meCannotOpenFile: k = errCannotOpenFile
-  of meExpected: k = errXExpected
-  of meGridTableNotImplemented: k = errGridTableNotImplemented
-  of meNewSectionExpected: k = errNewSectionExpected
-  of meGeneralParseError: k = errGeneralParseError
-  of meInvalidDirective: k = errInvalidDirectiveX
-  of mwRedefinitionOfLabel: k = warnRedefinitionOfLabel
-  of mwUnknownSubstitution: k = warnUnknownSubstitutionX
-  of mwUnsupportedLanguage: k = warnLanguageXNotSupported
-  of mwUnsupportedField: k = warnFieldXNotSupported
-  globalError(newLineInfo(filename, line, col), k, arg)
-
-proc docgenFindFile(s: string): string {.procvar.} =
-  result = options.findFile(s)
-  if result.len == 0:
-    result = getCurrentDir() / s
-    if not existsFile(result): result = ""
+template declareClosures =
+  proc compilerMsgHandler(filename: string, line, col: int,
+                          msgKind: rst.MsgKind, arg: string) {.procvar.} =
+    # translate msg kind:
+    var k: TMsgKind
+    case msgKind
+    of meCannotOpenFile: k = errCannotOpenFile
+    of meExpected: k = errXExpected
+    of meGridTableNotImplemented: k = errGridTableNotImplemented
+    of meNewSectionExpected: k = errNewSectionExpected
+    of meGeneralParseError: k = errGeneralParseError
+    of meInvalidDirective: k = errInvalidDirectiveX
+    of mwRedefinitionOfLabel: k = warnRedefinitionOfLabel
+    of mwUnknownSubstitution: k = warnUnknownSubstitutionX
+    of mwUnsupportedLanguage: k = warnLanguageXNotSupported
+    of mwUnsupportedField: k = warnFieldXNotSupported
+    globalError(conf, newLineInfo(conf, filename, line, col), k, arg)
+
+  proc docgenFindFile(s: string): string {.procvar.} =
+    result = options.findFile(conf, s)
+    if result.len == 0:
+      result = getCurrentDir() / s
+      if not existsFile(result): result = ""
 
 proc parseRst(text, filename: string,
               line, column: int, hasToc: var bool,
-              rstOptions: RstParseOptions): PRstNode =
+              rstOptions: RstParseOptions;
+              conf: ConfigRef): PRstNode =
+  declareClosures()
   result = rstParse(text, filename, line, column, hasToc, rstOptions,
                     docgenFindFile, compilerMsgHandler)
 
-proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
+proc newDocumentor*(filename: string, conf: ConfigRef): PDoc =
+  declareClosures()
   new(result)
-  initRstGenerator(result[], (if gCmd != cmdRst2tex: outHtml else: outLatex),
-                   options.gConfigVars, filename, {roSupportRawDirective},
+  result.conf = conf
+  initRstGenerator(result[], (if conf.cmd != cmdRst2tex: outHtml else: outLatex),
+                   conf.configVars, filename, {roSupportRawDirective},
                    docgenFindFile, compilerMsgHandler)
 
-  if config.hasKey("doc.googleAnalytics"):
+  if conf.configVars.hasKey("doc.googleAnalytics"):
     result.analytics = """
 <script>
   (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
@@ -100,7 +106,7 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
   ga('send', 'pageview');
 
 </script>
-    """ % [config.getOrDefault"doc.googleAnalytics"]
+    """ % [conf.configVars.getOrDefault"doc.googleAnalytics"]
   else:
     result.analytics = ""
 
@@ -109,10 +115,10 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
   result.jArray = newJArray()
   initStrTable result.types
   result.onTestSnippet = proc (d: var RstGenerator; filename, cmd: string; status: int; content: string) =
-    localError(newLineInfo(d.filename, -1, -1), warnUser, "only 'rst2html' supports the ':test:' attribute")
+    localError(conf, newLineInfo(conf, d.filename, -1, -1), warnUser, "only 'rst2html' supports the ':test:' attribute")
 
-proc dispA(dest: var Rope, xml, tex: string, args: openArray[Rope]) =
-  if gCmd != cmdRst2tex: addf(dest, xml, args)
+proc dispA(conf: ConfigRef; dest: var Rope, xml, tex: string, args: openArray[Rope]) =
+  if conf.cmd != cmdRst2tex: addf(dest, xml, args)
   else: addf(dest, tex, args)
 
 proc getVarIdx(varnames: openArray[string], id: string): int =
@@ -121,7 +127,8 @@ proc getVarIdx(varnames: openArray[string], id: string): int =
       return i
   result = -1
 
-proc ropeFormatNamedVars(frmt: FormatStr, varnames: openArray[string],
+proc ropeFormatNamedVars(conf: ConfigRef; frmt: FormatStr,
+                         varnames: openArray[string],
                          varvalues: openArray[Rope]): Rope =
   var i = 0
   var L = len(frmt)
@@ -144,7 +151,8 @@ proc ropeFormatNamedVars(frmt: FormatStr, varnames: openArray[string],
           j = (j * 10) + ord(frmt[i]) - ord('0')
           inc(i)
           if (i > L + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
-        if j > high(varvalues) + 1: internalError("ropeFormatNamedVars")
+        if j > high(varvalues) + 1:
+          rawMessage(conf, errGenerated, "Invalid format string; too many $s: " & frmt)
         num = j
         add(result, varvalues[j - 1])
       of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
@@ -155,20 +163,23 @@ proc ropeFormatNamedVars(frmt: FormatStr, varnames: openArray[string],
           if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break
         var idx = getVarIdx(varnames, id)
         if idx >= 0: add(result, varvalues[idx])
-        else: rawMessage(errUnknownSubstitionVar, id)
+        else: rawMessage(conf, errGenerated, "unknown substition variable: " & id)
       of '{':
         var id = ""
         inc(i)
-        while frmt[i] != '}':
-          if frmt[i] == '\0': rawMessage(errTokenExpected, "}")
+        while i < frmt.len and frmt[i] != '}':
           add(id, frmt[i])
           inc(i)
-        inc(i)                # skip }
-                              # search for the variable:
-        var idx = getVarIdx(varnames, id)
+        if i >= frmt.len:
+          rawMessage(conf, errGenerated, "expected closing '}'")
+        else:
+          inc(i)                # skip }
+        # search for the variable:
+        let idx = getVarIdx(varnames, id)
         if idx >= 0: add(result, varvalues[idx])
-        else: rawMessage(errUnknownSubstitionVar, id)
-      else: internalError("ropeFormatNamedVars")
+        else: rawMessage(conf, errGenerated, "unknown substition variable: " & id)
+      else:
+        add(result, "$")
     var start = i
     while i < L:
       if frmt[i] != '$': inc(i)
@@ -181,7 +192,7 @@ proc genComment(d: PDoc, n: PNode): string =
   if n.comment != nil:
     renderRstToOut(d[], parseRst(n.comment, toFilename(n.info),
                                toLinenumber(n.info), toColumn(n.info),
-                               dummyHasToc, d.options), result)
+                               dummyHasToc, d.options, d.conf), result)
 
 proc genRecComment(d: PDoc, n: PNode): Rope =
   if n == nil: return nil
@@ -220,37 +231,37 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
     of tkEof:
       break
     of tkComment:
-      dispA(result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}",
+      dispA(d.conf, result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}",
             [rope(esc(d.target, literal))])
     of tokKeywordLow..tokKeywordHigh:
-      dispA(result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}",
+      dispA(d.conf, result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}",
             [rope(literal)])
     of tkOpr:
-      dispA(result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}",
+      dispA(d.conf, result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}",
             [rope(esc(d.target, literal))])
     of tkStrLit..tkTripleStrLit:
-      dispA(result, "<span class=\"StringLit\">$1</span>",
+      dispA(d.conf, result, "<span class=\"StringLit\">$1</span>",
             "\\spanStringLit{$1}", [rope(esc(d.target, literal))])
     of tkCharLit:
-      dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
+      dispA(d.conf, result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
             [rope(esc(d.target, literal))])
     of tkIntLit..tkUInt64Lit:
-      dispA(result, "<span class=\"DecNumber\">$1</span>",
+      dispA(d.conf, result, "<span class=\"DecNumber\">$1</span>",
             "\\spanDecNumber{$1}", [rope(esc(d.target, literal))])
     of tkFloatLit..tkFloat128Lit:
-      dispA(result, "<span class=\"FloatNumber\">$1</span>",
+      dispA(d.conf, result, "<span class=\"FloatNumber\">$1</span>",
             "\\spanFloatNumber{$1}", [rope(esc(d.target, literal))])
     of tkSymbol:
-      dispA(result, "<span class=\"Identifier\">$1</span>",
+      dispA(d.conf, result, "<span class=\"Identifier\">$1</span>",
             "\\spanIdentifier{$1}", [rope(esc(d.target, literal))])
     of tkSpaces, tkInvalid:
       add(result, literal)
     of tkCurlyDotLe:
-      dispA(result, """<span class="Other pragmabegin">$1</span><div class="pragma">""",
+      dispA(d.conf, result, """<span class="Other pragmabegin">$1</span><div class="pragma">""",
                     "\\spanOther{$1}",
                   [rope(esc(d.target, literal))])
     of tkCurlyDotRi:
-      dispA(result, "</div><span class=\"Other pragmaend\">$1</span>",
+      dispA(d.conf, result, "</div><span class=\"Other pragmaend\">$1</span>",
                     "\\spanOther{$1}",
                   [rope(esc(d.target, literal))])
     of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
@@ -259,7 +270,7 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
        tkAccent, tkColonColon,
        tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr,
        tkBracketLeColon:
-      dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
+      dispA(d.conf, result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
             [rope(esc(d.target, literal))])
 
 proc getAllRunnableExamples(d: PDoc; n: PNode; dest: var Rope) =
@@ -267,7 +278,7 @@ proc getAllRunnableExamples(d: PDoc; n: PNode; dest: var Rope) =
   of nkCallKinds:
     if n[0].kind == nkSym and n[0].sym.magic == mRunnableExamples and
         n.len >= 2 and n.lastSon.kind == nkStmtList:
-      dispA(dest, "\n<strong class=\"examples_text\">$1</strong>\n",
+      dispA(d.conf, dest, "\n<strong class=\"examples_text\">$1</strong>\n",
           "\n\\textbf{$1}\n", [rope"Examples:"])
       inc d.listingCounter
       let id = $d.listingCounter
@@ -336,7 +347,6 @@ proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
   of nkOpenSymChoice, nkClosedSymChoice:
     result = getName(d, n[0], splitAfter)
   else:
-    internalError(n.info, "getName()")
     result = ""
 
 proc getNameIdent(n: PNode): PIdent =
@@ -366,7 +376,6 @@ proc getRstName(n: PNode): PRstNode =
   of nkOpenSymChoice, nkClosedSymChoice:
     result = getRstName(n[0])
   else:
-    internalError(n.info, "getRstName()")
     result = nil
 
 proc newUniquePlainSymbol(d: PDoc, original: string): string =
@@ -490,22 +499,22 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
     symbolOrIdEncRope = encodeUrl(symbolOrId).rope
 
   var seeSrcRope: Rope = nil
-  let docItemSeeSrc = getConfigVar("doc.item.seesrc")
+  let docItemSeeSrc = getConfigVar(d.conf, "doc.item.seesrc")
   if docItemSeeSrc.len > 0:
-    let cwd = getCurrentDir().canonicalizePath()
+    let cwd = canonicalizePath(d.conf, getCurrentDir())
     var path = n.info.toFullPath
     if path.startsWith(cwd):
       path = path[cwd.len+1 .. ^1].replace('\\', '/')
-    let gitUrl = getConfigVar("git.url")
+    let gitUrl = getConfigVar(d.conf, "git.url")
     if gitUrl.len > 0:
-      var commit = getConfigVar("git.commit")
+      var commit = getConfigVar(d.conf, "git.commit")
       if commit.len == 0: commit = "master"
-      dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc,
+      dispA(d.conf, seeSrcRope, "$1", "", [ropeFormatNamedVars(d.conf, docItemSeeSrc,
           ["path", "line", "url", "commit"], [rope path,
           rope($n.info.line), rope gitUrl,
           rope commit])])
 
-  add(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
+  add(d.section[k], ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item"),
     ["name", "header", "desc", "itemID", "header_plain", "itemSym",
       "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "seeSrc"],
     [nameRope, result, comm, itemIDRope, plainNameRope, plainSymbolRope,
@@ -516,7 +525,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
     let att = attachToType(d, nameNode.sym)
     if att != nil:
       attype = rope esc(d.target, att.name.s)
-  add(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
+  add(d.toc[k], ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item.toc"),
     ["name", "header", "desc", "itemID", "header_plain", "itemSym",
       "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "attype"],
     [rope(getName(d, nameNode, d.splitAfter)), result, comm,
@@ -569,9 +578,9 @@ proc traceDeps(d: PDoc, it: PNode) =
       traceDeps(d, a)
   else:
     if d.section[k] != nil: add(d.section[k], ", ")
-    dispA(d.section[k],
+    dispA(d.conf, d.section[k],
           "<a class=\"reference external\" href=\"$1.html\">$1</a>",
-          "$1", [rope(getModuleName(it))])
+          "$1", [rope(getModuleName(d.conf, it))])
 
 proc generateDoc*(d: PDoc, n: PNode) =
   case n.kind
@@ -704,10 +713,10 @@ proc genSection(d: PDoc, kind: TSymKind) =
   ]
   if d.section[kind] == nil: return
   var title = sectionNames[kind].rope
-  d.section[kind] = ropeFormatNamedVars(getConfigVar("doc.section"), [
+  d.section[kind] = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.section"), [
       "sectionid", "sectionTitle", "sectionTitleID", "content"], [
       ord(kind).rope, title, rope(ord(kind) + 50), d.section[kind]])
-  d.toc[kind] = ropeFormatNamedVars(getConfigVar("doc.section.toc"), [
+  d.toc[kind] = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.section.toc"), [
       "sectionid", "sectionTitle", "sectionTitleID", "content"], [
       ord(kind).rope, title, rope(ord(kind) + 50), d.toc[kind]])
 
@@ -723,7 +732,7 @@ proc genOutFile(d: PDoc): Rope =
     genSection(d, i)
     add(toc, d.toc[i])
   if toc != nil:
-    toc = ropeFormatNamedVars(getConfigVar("doc.toc"), ["content"], [toc])
+    toc = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.toc"), ["content"], [toc])
   for i in countup(low(TSymKind), high(TSymKind)): add(code, d.section[i])
 
   # Extract the title. Non API modules generate an entry in the index table.
@@ -737,13 +746,13 @@ proc genOutFile(d: PDoc): Rope =
   let bodyname = if d.hasToc and not d.isPureRst: "doc.body_toc_group"
                  elif d.hasToc: "doc.body_toc"
                  else: "doc.body_no_toc"
-  content = ropeFormatNamedVars(getConfigVar(bodyname), ["title",
+  content = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, bodyname), ["title",
       "tableofcontents", "moduledesc", "date", "time", "content"],
       [title.rope, toc, d.modDesc, rope(getDateStr()),
       rope(getClockStr()), code])
-  if optCompileOnly notin gGlobalOptions:
+  if optCompileOnly notin d.conf.globalOptions:
     # XXX what is this hack doing here? 'optCompileOnly' means raw output!?
-    code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
+    code = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.file"), ["title",
         "tableofcontents", "moduledesc", "date", "time",
         "content", "author", "version", "analytics"],
         [title.rope, toc, d.modDesc, rope(getDateStr()),
@@ -754,60 +763,60 @@ proc genOutFile(d: PDoc): Rope =
   result = code
 
 proc generateIndex*(d: PDoc) =
-  if optGenIndex in gGlobalOptions:
-    writeIndexFile(d[], splitFile(options.outFile).dir /
+  if optGenIndex in d.conf.globalOptions:
+    writeIndexFile(d[], splitFile(d.conf.outFile).dir /
                         splitFile(d.filename).name & IndexExt)
 
-proc getOutFile2(filename, ext, dir: string): string =
-  if gWholeProject:
-    let d = if options.outFile != "": options.outFile else: dir
+proc getOutFile2(conf: ConfigRef; filename, ext, dir: string): string =
+  if optWholeProject in conf.globalOptions:
+    let d = if conf.outFile != "": conf.outFile else: dir
     createDir(d)
     result = d / changeFileExt(filename, ext)
   else:
-    result = getOutFile(filename, ext)
+    result = getOutFile(conf, filename, ext)
 
 proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
   var content = genOutFile(d)
-  if optStdout in gGlobalOptions:
+  if optStdout in d.conf.globalOptions:
     writeRope(stdout, content)
   else:
-    writeRope(content, getOutFile2(filename, outExt, "htmldocs"), useWarning)
+    writeRope(content, getOutFile2(d.conf, filename, outExt, "htmldocs"), useWarning)
 
 proc writeOutputJson*(d: PDoc, filename, outExt: string,
                       useWarning = false) =
   let content = %*{"orig": d.filename,
-    "nimble": getPackageName(d.filename),
+    "nimble": getPackageName(d.conf, d.filename),
     "entries": d.jArray}
-  if optStdout in gGlobalOptions:
+  if optStdout in d.conf.globalOptions:
     write(stdout, $content)
   else:
     var f: File
-    if open(f, getOutFile2(splitFile(filename).name,
+    if open(f, getOutFile2(d.conf, splitFile(filename).name,
             outExt, "jsondocs"), fmWrite):
       write(f, $content)
       close(f)
     else:
       discard "fixme: error report"
 
-proc commandDoc*() =
-  var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef())
+proc commandDoc*(conf: ConfigRef) =
+  var ast = parseFile(conf.projectMainIdx.FileIndex, newIdentCache(), conf)
   if ast == nil: return
-  var d = newDocumentor(gProjectFull, options.gConfigVars)
+  var d = newDocumentor(conf.projectFull, conf)
   d.hasToc = true
   generateDoc(d, ast)
-  writeOutput(d, gProjectFull, HtmlExt)
+  writeOutput(d, conf.projectFull, HtmlExt)
   generateIndex(d)
 
-proc commandRstAux(filename, outExt: string) =
+proc commandRstAux(conf: ConfigRef; filename, outExt: string) =
   var filen = addFileExt(filename, "txt")
-  var d = newDocumentor(filen, options.gConfigVars)
+  var d = newDocumentor(filen, conf)
   d.onTestSnippet = proc (d: var RstGenerator; filename, cmd: string;
                           status: int; content: string) =
     var outp: string
     if filename.len == 0:
       inc(d.id)
       let nameOnly = splitFile(d.filename).name
-      let subdir = getNimcacheDir() / nameOnly
+      let subdir = getNimcacheDir(conf) / nameOnly
       createDir(subdir)
       outp = subdir / (nameOnly & "_snippet_" & $d.id & ".nim")
     elif isAbsolute(filename):
@@ -817,13 +826,13 @@ proc commandRstAux(filename, outExt: string) =
       outp = splitFile(d.filename).dir / filename
     writeFile(outp, content)
     let cmd = cmd % quoteShell(outp)
-    rawMessage(hintExecuting, cmd)
+    rawMessage(conf, hintExecuting, cmd)
     if execShellCmd(cmd) != status:
-      rawMessage(errExecutionOfProgramFailed, cmd)
+      rawMessage(conf, errGenerated, "executing of external program failed: " & cmd)
 
   d.isPureRst = true
   var rst = parseRst(readFile(filen), filen, 0, 1, d.hasToc,
-                     {roSupportRawDirective})
+                     {roSupportRawDirective}, conf)
   var modDesc = newStringOfCap(30_000)
   #d.modDesc = newMutableRope(30_000)
   renderRstToOut(d[], rst, modDesc)
@@ -832,50 +841,50 @@ proc commandRstAux(filename, outExt: string) =
   writeOutput(d, filename, outExt)
   generateIndex(d)
 
-proc commandRst2Html*() =
-  commandRstAux(gProjectFull, HtmlExt)
+proc commandRst2Html*(conf: ConfigRef) =
+  commandRstAux(conf, conf.projectFull, HtmlExt)
 
-proc commandRst2TeX*() =
+proc commandRst2TeX*(conf: ConfigRef) =
   splitter = "\\-"
-  commandRstAux(gProjectFull, TexExt)
+  commandRstAux(conf, conf.projectFull, TexExt)
 
-proc commandJson*() =
-  var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef())
+proc commandJson*(conf: ConfigRef) =
+  var ast = parseFile(conf.projectMainIdx.FileIndex, newIdentCache(), conf)
   if ast == nil: return
-  var d = newDocumentor(gProjectFull, options.gConfigVars)
+  var d = newDocumentor(conf.projectFull, conf)
   d.hasToc = true
   generateJson(d, ast)
   let json = d.jArray
   let content = rope(pretty(json))
 
-  if optStdout in gGlobalOptions:
+  if optStdout in d.conf.globalOptions:
     writeRope(stdout, content)
   else:
     #echo getOutFile(gProjectFull, JsonExt)
-    writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
+    writeRope(content, getOutFile(conf, conf.projectFull, JsonExt), useWarning = false)
 
-proc commandTags*() =
-  var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef())
+proc commandTags*(conf: ConfigRef) =
+  var ast = parseFile(conf.projectMainIdx.FileIndex, newIdentCache(), conf)
   if ast == nil: return
-  var d = newDocumentor(gProjectFull, options.gConfigVars)
+  var d = newDocumentor(conf.projectFull, conf)
   d.hasToc = true
   var
     content: Rope
   generateTags(d, ast, content)
 
-  if optStdout in gGlobalOptions:
+  if optStdout in d.conf.globalOptions:
     writeRope(stdout, content)
   else:
     #echo getOutFile(gProjectFull, TagsExt)
-    writeRope(content, getOutFile(gProjectFull, TagsExt), useWarning = false)
+    writeRope(content, getOutFile(conf, conf.projectFull, TagsExt), useWarning = false)
 
-proc commandBuildIndex*() =
-  var content = mergeIndexes(gProjectFull).rope
+proc commandBuildIndex*(conf: ConfigRef) =
+  var content = mergeIndexes(conf.projectFull).rope
 
-  let code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
+  let code = ropeFormatNamedVars(conf, getConfigVar(conf, "doc.file"), ["title",
       "tableofcontents", "moduledesc", "date", "time",
       "content", "author", "version", "analytics"],
       ["Index".rope, nil, nil, rope(getDateStr()),
                    rope(getClockStr()), content, nil, nil, nil])
   # no analytics because context is not available
-  writeRope(code, getOutFile("theindex", HtmlExt))
+  writeRope(code, getOutFile(conf, "theindex", HtmlExt))
diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim
index 118f1c7c5..d9a73e1cd 100644
--- a/compiler/docgen2.nim
+++ b/compiler/docgen2.nim
@@ -25,8 +25,8 @@ template closeImpl(body: untyped) {.dirty.} =
   var g = PGen(p)
   let useWarning = sfMainModule notin g.module.flags
   #echo g.module.name.s, " ", g.module.owner.id, " ", gMainPackageId
-  if (g.module.owner.id == gMainPackageId and gWholeProject) or
-    sfMainModule in g.module.flags:
+  if (g.module.owner.id == gMainPackageId and optWholeProject in g.doc.conf.globalOptions) or
+      sfMainModule in g.module.flags:
     body
     try:
       generateIndex(g.doc)
@@ -55,7 +55,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
   var g: PGen
   new(g)
   g.module = module
-  var d = newDocumentor(module.filename, options.gConfigVars)
+  var d = newDocumentor(module.filename, graph.config)
   d.hasToc = true
   g.doc = d
   result = g
diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim
index 502430815..01c56ec9c 100644
--- a/compiler/evaltempl.nim
+++ b/compiler/evaltempl.nim
@@ -14,11 +14,12 @@ import
   rodread
 
 type
-  TemplCtx {.pure, final.} = object
+  TemplCtx = object
     owner, genSymOwner: PSym
     instLines: bool   # use the instantiation lines numbers
     mapping: TIdTable # every gensym'ed symbol needs to be mapped to some
                       # new symbol
+    config: ConfigRef
 
 proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
   result = copyNode(a)
@@ -42,7 +43,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
            s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam:
         handleParam actual.sons[s.owner.typ.len + s.position - 1]
       else:
-        internalAssert sfGenSym in s.flags or s.kind == skType
+        internalAssert c.config, sfGenSym in s.flags or s.kind == skType
         var x = PSym(idTableGet(c.mapping, s))
         if x == nil:
           x = copySym(s, false)
@@ -59,7 +60,12 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
       evalTemplateAux(templ.sons[i], actual, c, res)
     result.add res
 
-proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
+const
+  errWrongNumberOfArguments = "wrong number of arguments"
+  errMissingGenericParamsForTemplate = "'$1' has unspecified generic parameters"
+  errTemplateInstantiationTooNested = "template instantiation too nested"
+
+proc evalTemplateArgs(n: PNode, s: PSym; conf: ConfigRef; fromHlo: bool): PNode =
   # if the template has zero arguments, it can be called without ``()``
   # `n` is then a nkSym or something similar
   var totalParams = case n.kind
@@ -82,10 +88,10 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
   if givenRegularParams < 0: givenRegularParams = 0
 
   if totalParams > expectedRegularParams + genericParams:
-    globalError(n.info, errWrongNumberOfArguments)
+    globalError(conf, n.info, errWrongNumberOfArguments)
 
   if totalParams < genericParams:
-    globalError(n.info, errMissingGenericParamsForTemplate,
+    globalError(conf, n.info, errMissingGenericParamsForTemplate %
                 n.renderTree)
 
   result = newNodeI(nkArgList, n.info)
@@ -97,7 +103,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
   for i in givenRegularParams+1 .. expectedRegularParams:
     let default = s.typ.n.sons[i].sym.ast
     if default.isNil or default.kind == nkEmpty:
-      localError(n.info, errWrongNumberOfArguments)
+      localError(conf, n.info, errWrongNumberOfArguments)
       addSon(result, ast.emptyNode)
     else:
       addSon(result, default.copyTree)
@@ -108,7 +114,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
 
 # to prevent endless recursion in template instantiation
 const evalTemplateLimit* = 1000
-var evalTemplateCounter* = 0
+var evalTemplateCounter* = 0 # XXX remove this global
 
 proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
   when true:
@@ -132,17 +138,19 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
     result.add res
     result.typ = res.typ
 
-proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode =
+proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
+                   conf: ConfigRef; fromHlo=false): PNode =
   inc(evalTemplateCounter)
   if evalTemplateCounter > evalTemplateLimit:
-    globalError(n.info, errTemplateInstantiationTooNested)
+    globalError(conf, n.info, errTemplateInstantiationTooNested)
     result = n
 
   # replace each param by the corresponding node:
-  var args = evalTemplateArgs(n, tmpl, fromHlo)
+  var args = evalTemplateArgs(n, tmpl, conf, fromHlo)
   var ctx: TemplCtx
   ctx.owner = tmpl
   ctx.genSymOwner = genSymOwner
+  ctx.config = conf
   initIdTable(ctx.mapping)
 
   let body = tmpl.getBody
@@ -151,7 +159,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode =
     evalTemplateAux(body, args, ctx, result)
     if result.len == 1: result = result.sons[0]
     else:
-      localError(result.info, errIllFormedAstX,
+      localError(conf, result.info, "illformed AST: " &
                   renderTree(result, {renderNoComments}))
   else:
     result = copyNode(body)
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index f8938e3af..3f0e6f611 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -14,7 +14,7 @@
 
 import
   ropes, os, strutils, osproc, platform, condsyms, options, msgs,
-  std / sha1, streams
+  configuration, std / sha1, streams
 
 #from debuginfo import writeDebugInfo
 
@@ -193,9 +193,9 @@ compiler bcc:
     pic: "",
     asmStmtFrmt: "__asm{$n$1$n}$n",
     structStmtFmt: "$1 $2",
-    props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, 
+    props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard,
             hasAttribute})
-    
+
 
 # Digital Mars C Compiler
 compiler dmc:
@@ -376,80 +376,81 @@ proc nameToCC*(name: string): TSystemCC =
       return i
   result = ccNone
 
-proc getConfigVar(c: TSystemCC, suffix: string): string =
+proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string =
   # use ``cpu.os.cc`` for cross compilation, unless ``--compileOnly`` is given
   # for niminst support
   let fullSuffix =
-    if gCmd == cmdCompileToCpp:
+    if conf.cmd == cmdCompileToCpp:
       ".cpp" & suffix
-    elif gCmd == cmdCompileToOC:
+    elif conf.cmd == cmdCompileToOC:
       ".objc" & suffix
-    elif gCmd == cmdCompileToJS:
+    elif conf.cmd == cmdCompileToJS:
       ".js" & suffix
     else:
       suffix
 
   if (platform.hostOS != targetOS or platform.hostCPU != targetCPU) and
-      optCompileOnly notin gGlobalOptions:
+      optCompileOnly notin conf.globalOptions:
     let fullCCname = platform.CPU[targetCPU].name & '.' &
                      platform.OS[targetOS].name & '.' &
                      CC[c].name & fullSuffix
-    result = getConfigVar(fullCCname)
+    result = getConfigVar(conf, fullCCname)
     if result.len == 0:
       # not overriden for this cross compilation setting?
-      result = getConfigVar(CC[c].name & fullSuffix)
+      result = getConfigVar(conf, CC[c].name & fullSuffix)
   else:
-    result = getConfigVar(CC[c].name & fullSuffix)
+    result = getConfigVar(conf, CC[c].name & fullSuffix)
 
-proc setCC*(ccname: string) =
+proc setCC*(conf: ConfigRef; ccname: string; info: TLineInfo) =
   cCompiler = nameToCC(ccname)
-  if cCompiler == ccNone: rawMessage(errUnknownCcompiler, ccname)
-  compileOptions = getConfigVar(cCompiler, ".options.always")
+  if cCompiler == ccNone:
+    localError(conf, info, "unknown C compiler: '$1'" % ccname)
+  compileOptions = getConfigVar(conf, cCompiler, ".options.always")
   linkOptions = ""
-  ccompilerpath = getConfigVar(cCompiler, ".path")
-  for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
-  defineSymbol(CC[cCompiler].name)
+  ccompilerpath = getConfigVar(conf, cCompiler, ".path")
+  for i in countup(low(CC), high(CC)): undefSymbol(conf.symbols, CC[i].name)
+  defineSymbol(conf.symbols, CC[cCompiler].name)
 
 proc addOpt(dest: var string, src: string) =
   if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ")
   add(dest, src)
 
-proc addLinkOption*(option: string) =
+proc addLinkOption*(conf: ConfigRef; option: string) =
   addOpt(linkOptions, option)
 
-proc addCompileOption*(option: string) =
+proc addCompileOption*(conf: ConfigRef; option: string) =
   if strutils.find(compileOptions, option, 0) < 0:
     addOpt(compileOptions, option)
 
-proc addLinkOptionCmd*(option: string) =
+proc addLinkOptionCmd*(conf: ConfigRef; option: string) =
   addOpt(linkOptionsCmd, option)
 
-proc addCompileOptionCmd*(option: string) =
+proc addCompileOptionCmd*(conf: ConfigRef; option: string) =
   compileOptionsCmd.add(option)
 
-proc initVars*() =
+proc initVars*(conf: ConfigRef) =
   # we need to define the symbol here, because ``CC`` may have never been set!
-  for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
-  defineSymbol(CC[cCompiler].name)
-  addCompileOption(getConfigVar(cCompiler, ".options.always"))
+  for i in countup(low(CC), high(CC)): undefSymbol(conf.symbols, CC[i].name)
+  defineSymbol(conf.symbols, CC[cCompiler].name)
+  addCompileOption(conf, getConfigVar(conf, cCompiler, ".options.always"))
   #addLinkOption(getConfigVar(cCompiler, ".options.linker"))
   if len(ccompilerpath) == 0:
-    ccompilerpath = getConfigVar(cCompiler, ".path")
+    ccompilerpath = getConfigVar(conf, cCompiler, ".path")
 
-proc completeCFilePath*(cfile: string, createSubDir: bool = true): string =
-  result = completeGeneratedFilePath(cfile, createSubDir)
+proc completeCFilePath*(conf: ConfigRef; cfile: string, createSubDir: bool = true): string =
+  result = completeGeneratedFilePath(conf, cfile, createSubDir)
 
-proc toObjFile*(filename: string): string =
+proc toObjFile*(conf: ConfigRef; filename: string): string =
   # Object file for compilation
   #if filename.endsWith(".cpp"):
   #  result = changeFileExt(filename, "cpp." & CC[cCompiler].objExt)
   #else:
   result = changeFileExt(filename, CC[cCompiler].objExt)
 
-proc addFileToCompile*(cf: Cfile) =
+proc addFileToCompile*(conf: ConfigRef; cf: Cfile) =
   toCompile.add(cf)
 
-proc resetCompilationLists* =
+proc resetCompilationLists*(conf: ConfigRef) =
   toCompile.setLen 0
   ## XXX: we must associate these with their originating module
   # when the module is loaded/unloaded it adds/removes its items
@@ -457,109 +458,112 @@ proc resetCompilationLists* =
   # Maybe we can do that in checkDep on the other hand?
   externalToLink.setLen 0
 
-proc addExternalFileToLink*(filename: string) =
+proc addExternalFileToLink*(conf: ConfigRef; filename: string) =
   externalToLink.insert(filename, 0)
 
-proc execWithEcho(cmd: string, msg = hintExecuting): int =
-  rawMessage(msg, cmd)
+proc execWithEcho(conf: ConfigRef; cmd: string, msg = hintExecuting): int =
+  rawMessage(conf, msg, cmd)
   result = execCmd(cmd)
 
-proc execExternalProgram*(cmd: string, msg = hintExecuting) =
-  if execWithEcho(cmd, msg) != 0:
-    rawMessage(errExecutionOfProgramFailed, cmd)
+proc execExternalProgram*(conf: ConfigRef; cmd: string, msg = hintExecuting) =
+  if execWithEcho(conf, cmd, msg) != 0:
+    rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" %
+      cmd)
 
-proc generateScript(projectFile: string, script: Rope) =
+proc generateScript(conf: ConfigRef; projectFile: string, script: Rope) =
   let (dir, name, ext) = splitFile(projectFile)
-  writeRope(script, getNimcacheDir() / addFileExt("compile_" & name,
+  writeRope(script, getNimcacheDir(conf) / addFileExt("compile_" & name,
                                      platform.OS[targetOS].scriptExt))
-  copyFile(libpath / "nimbase.h", getNimcacheDir() / "nimbase.h")
+  copyFile(conf.libpath / "nimbase.h", getNimcacheDir(conf) / "nimbase.h")
 
-proc getOptSpeed(c: TSystemCC): string =
-  result = getConfigVar(c, ".options.speed")
+proc getOptSpeed(conf: ConfigRef; c: TSystemCC): string =
+  result = getConfigVar(conf, c, ".options.speed")
   if result == "":
     result = CC[c].optSpeed   # use default settings from this file
 
-proc getDebug(c: TSystemCC): string =
-  result = getConfigVar(c, ".options.debug")
+proc getDebug(conf: ConfigRef; c: TSystemCC): string =
+  result = getConfigVar(conf, c, ".options.debug")
   if result == "":
     result = CC[c].debug      # use default settings from this file
 
-proc getOptSize(c: TSystemCC): string =
-  result = getConfigVar(c, ".options.size")
+proc getOptSize(conf: ConfigRef; c: TSystemCC): string =
+  result = getConfigVar(conf, c, ".options.size")
   if result == "":
     result = CC[c].optSize    # use default settings from this file
 
-proc noAbsolutePaths: bool {.inline.} =
+proc noAbsolutePaths(conf: ConfigRef): bool {.inline.} =
   # We used to check current OS != specified OS, but this makes no sense
   # really: Cross compilation from Linux to Linux for example is entirely
   # reasonable.
   # `optGenMapping` is included here for niminst.
-  result = gGlobalOptions * {optGenScript, optGenMapping} != {}
+  result = conf.globalOptions * {optGenScript, optGenMapping} != {}
 
-proc cFileSpecificOptions(cfilename: string): string =
+proc cFileSpecificOptions(conf: ConfigRef; cfilename: string): string =
   result = compileOptions
   for option in compileOptionsCmd:
     if strutils.find(result, option, 0) < 0:
       addOpt(result, option)
 
-  var trunk = splitFile(cfilename).name
-  if optCDebug in gGlobalOptions:
-    var key = trunk & ".debug"
-    if existsConfigVar(key): addOpt(result, getConfigVar(key))
-    else: addOpt(result, getDebug(cCompiler))
-  if optOptimizeSpeed in gOptions:
-    var key = trunk & ".speed"
-    if existsConfigVar(key): addOpt(result, getConfigVar(key))
-    else: addOpt(result, getOptSpeed(cCompiler))
-  elif optOptimizeSize in gOptions:
-    var key = trunk & ".size"
-    if existsConfigVar(key): addOpt(result, getConfigVar(key))
-    else: addOpt(result, getOptSize(cCompiler))
-  var key = trunk & ".always"
-  if existsConfigVar(key): addOpt(result, getConfigVar(key))
-
-proc getCompileOptions: string =
-  result = cFileSpecificOptions("__dummy__")
-
-proc getLinkOptions: string =
+  let trunk = splitFile(cfilename).name
+  if optCDebug in conf.globalOptions:
+    let key = trunk & ".debug"
+    if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
+    else: addOpt(result, getDebug(conf, cCompiler))
+  if optOptimizeSpeed in conf.options:
+    let key = trunk & ".speed"
+    if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
+    else: addOpt(result, getOptSpeed(conf, cCompiler))
+  elif optOptimizeSize in conf.options:
+    let key = trunk & ".size"
+    if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
+    else: addOpt(result, getOptSize(conf, cCompiler))
+  let key = trunk & ".always"
+  if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
+
+proc getCompileOptions(conf: ConfigRef): string =
+  result = cFileSpecificOptions(conf, "__dummy__")
+
+proc getLinkOptions(conf: ConfigRef): string =
   result = linkOptions & " " & linkOptionsCmd & " "
   for linkedLib in items(cLinkedLibs):
     result.add(CC[cCompiler].linkLibCmd % linkedLib.quoteShell)
   for libDir in items(cLibs):
     result.add(join([CC[cCompiler].linkDirCmd, libDir.quoteShell]))
 
-proc needsExeExt(): bool {.inline.} =
-  result = (optGenScript in gGlobalOptions and targetOS == osWindows) or
+proc needsExeExt(conf: ConfigRef): bool {.inline.} =
+  result = (optGenScript in conf.globalOptions and targetOS == osWindows) or
            (platform.hostOS == osWindows)
 
-proc getCompilerExe(compiler: TSystemCC; cfile: string): string =
-  result = if gCmd == cmdCompileToCpp and not cfile.endsWith(".c"):
+proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: string): string =
+  result = if conf.cmd == cmdCompileToCpp and not cfile.endsWith(".c"):
              CC[compiler].cppCompiler
            else:
              CC[compiler].compilerExe
   if result.len == 0:
-    rawMessage(errCompilerDoesntSupportTarget, CC[compiler].name)
+    rawMessage(conf, errGenerated,
+      "Compiler '$1' doesn't support the requested target" %
+      CC[compiler].name)
 
-proc getLinkerExe(compiler: TSystemCC): string =
+proc getLinkerExe(conf: ConfigRef; compiler: TSystemCC): string =
   result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe
-           elif gMixedMode and gCmd != cmdCompileToCpp: CC[compiler].cppCompiler
-           else: compiler.getCompilerExe("")
+           elif gMixedMode and conf.cmd != cmdCompileToCpp: CC[compiler].cppCompiler
+           else: getCompilerExe(conf, compiler, "")
 
-proc getCompileCFileCmd*(cfile: Cfile): string =
+proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile): string =
   var c = cCompiler
-  var options = cFileSpecificOptions(cfile.cname)
-  var exe = getConfigVar(c, ".exe")
-  if exe.len == 0: exe = c.getCompilerExe(cfile.cname)
+  var options = cFileSpecificOptions(conf, cfile.cname)
+  var exe = getConfigVar(conf, c, ".exe")
+  if exe.len == 0: exe = getCompilerExe(conf, c, cfile.cname)
 
-  if needsExeExt(): exe = addFileExt(exe, "exe")
-  if optGenDynLib in gGlobalOptions and
+  if needsExeExt(conf): exe = addFileExt(exe, "exe")
+  if optGenDynLib in conf.globalOptions and
       ospNeedsPIC in platform.OS[targetOS].props:
     add(options, ' ' & CC[c].pic)
 
   var includeCmd, compilePattern: string
-  if not noAbsolutePaths():
+  if not noAbsolutePaths(conf):
     # compute include paths:
-    includeCmd = CC[c].includeCmd & quoteShell(libpath)
+    includeCmd = CC[c].includeCmd & quoteShell(conf.libpath)
 
     for includeDir in items(cIncludes):
       includeCmd.add(join([CC[c].includeCmd, includeDir.quoteShell]))
@@ -567,18 +571,18 @@ proc getCompileCFileCmd*(cfile: Cfile): string =
     compilePattern = joinPath(ccompilerpath, exe)
   else:
     includeCmd = ""
-    compilePattern = c.getCompilerExe(cfile.cname)
+    compilePattern = getCompilerExe(conf, c, cfile.cname)
 
-  var cf = if noAbsolutePaths(): extractFilename(cfile.cname)
+  var cf = if noAbsolutePaths(conf): extractFilename(cfile.cname)
            else: cfile.cname
 
   var objfile =
     if cfile.obj.len == 0:
-      if not cfile.flags.contains(CfileFlag.External) or noAbsolutePaths():
-        toObjFile(cf)
+      if not cfile.flags.contains(CfileFlag.External) or noAbsolutePaths(conf):
+        toObjFile(conf, cf)
       else:
-        completeCFilePath(toObjFile(cf))
-    elif noAbsolutePaths():
+        completeCFilePath(conf, toObjFile(conf, cf))
+    elif noAbsolutePaths(conf):
       extractFilename(cfile.obj)
     else:
       cfile.obj
@@ -587,30 +591,30 @@ proc getCompileCFileCmd*(cfile: Cfile): string =
   cf = quoteShell(cf)
   result = quoteShell(compilePattern % [
     "file", cf, "objfile", objfile, "options", options,
-    "include", includeCmd, "nim", getPrefixDir(),
-    "nim", getPrefixDir(), "lib", libpath])
+    "include", includeCmd, "nim", getPrefixDir(conf),
+    "nim", getPrefixDir(conf), "lib", conf.libpath])
   add(result, ' ')
   addf(result, CC[c].compileTmpl, [
     "file", cf, "objfile", objfile,
     "options", options, "include", includeCmd,
-    "nim", quoteShell(getPrefixDir()),
-    "nim", quoteShell(getPrefixDir()),
-    "lib", quoteShell(libpath)])
+    "nim", quoteShell(getPrefixDir(conf)),
+    "nim", quoteShell(getPrefixDir(conf)),
+    "lib", quoteShell(conf.libpath)])
 
-proc footprint(cfile: Cfile): SecureHash =
+proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash =
   result = secureHash(
     $secureHashFile(cfile.cname) &
     platform.OS[targetOS].name &
     platform.CPU[targetCPU].name &
     extccomp.CC[extccomp.cCompiler].name &
-    getCompileCFileCmd(cfile))
+    getCompileCFileCmd(conf, cfile))
 
-proc externalFileChanged(cfile: Cfile): bool =
-  if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}:
+proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool =
+  if conf.cmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}:
     return false
 
-  var hashFile = toGeneratedFile(cfile.cname.withPackageName, "sha1")
-  var currentHash = footprint(cfile)
+  var hashFile = toGeneratedFile(conf, conf.withPackageName(cfile.cname), "sha1")
+  var currentHash = footprint(conf, cfile)
   var f: File
   if open(f, hashFile, fmRead):
     let oldHash = parseSecureHash(f.readLine())
@@ -623,133 +627,137 @@ proc externalFileChanged(cfile: Cfile): bool =
       f.writeLine($currentHash)
       close(f)
 
-proc addExternalFileToCompile*(c: var Cfile) =
-  if optForceFullMake notin gGlobalOptions and not externalFileChanged(c):
+proc addExternalFileToCompile*(conf: ConfigRef; c: var Cfile) =
+  if optForceFullMake notin conf.globalOptions and not externalFileChanged(conf, c):
     c.flags.incl CfileFlag.Cached
   toCompile.add(c)
 
-proc addExternalFileToCompile*(filename: string) =
+proc addExternalFileToCompile*(conf: ConfigRef; filename: string) =
   var c = Cfile(cname: filename,
-    obj: toObjFile(completeCFilePath(changeFileExt(filename, ""), false)),
+    obj: toObjFile(conf, completeCFilePath(conf, changeFileExt(filename, ""), false)),
     flags: {CfileFlag.External})
-  addExternalFileToCompile(c)
+  addExternalFileToCompile(conf, c)
 
-proc compileCFile(list: CFileList, script: var Rope, cmds: var TStringSeq,
+proc compileCFile(conf: ConfigRef; list: CFileList, script: var Rope, cmds: var TStringSeq,
                   prettyCmds: var TStringSeq) =
   for it in list:
     # call the C compiler for the .c file:
     if it.flags.contains(CfileFlag.Cached): continue
-    var compileCmd = getCompileCFileCmd(it)
-    if optCompileOnly notin gGlobalOptions:
+    var compileCmd = getCompileCFileCmd(conf, it)
+    if optCompileOnly notin conf.globalOptions:
       add(cmds, compileCmd)
       let (_, name, _) = splitFile(it.cname)
       add(prettyCmds, "CC: " & name)
-    if optGenScript in gGlobalOptions:
+    if optGenScript in conf.globalOptions:
       add(script, compileCmd)
       add(script, tnl)
 
-proc getLinkCmd(projectfile, objfiles: string): string =
-  if optGenStaticLib in gGlobalOptions:
+proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string =
+  if optGenStaticLib in conf.globalOptions:
     var libname: string
-    if options.outFile.len > 0:
-      libname = options.outFile.expandTilde
+    if conf.outFile.len > 0:
+      libname = conf.outFile.expandTilde
       if not libname.isAbsolute():
         libname = getCurrentDir() / libname
     else:
-      libname = (libNameTmpl() % splitFile(gProjectName).name)
+      libname = (libNameTmpl() % splitFile(conf.projectName).name)
     result = CC[cCompiler].buildLib % ["libfile", libname,
                                        "objfiles", objfiles]
   else:
-    var linkerExe = getConfigVar(cCompiler, ".linkerexe")
-    if len(linkerExe) == 0: linkerExe = cCompiler.getLinkerExe
+    var linkerExe = getConfigVar(conf, cCompiler, ".linkerexe")
+    if len(linkerExe) == 0: linkerExe = getLinkerExe(conf, cCompiler)
     # bug #6452: We must not use ``quoteShell`` here for ``linkerExe``
-    if needsExeExt(): linkerExe = addFileExt(linkerExe, "exe")
-    if noAbsolutePaths(): result = linkerExe
+    if needsExeExt(conf): linkerExe = addFileExt(linkerExe, "exe")
+    if noAbsolutePaths(conf): result = linkerExe
     else: result = joinPath(ccompilerpath, linkerExe)
-    let buildgui = if optGenGuiApp in gGlobalOptions: CC[cCompiler].buildGui
+    let buildgui = if optGenGuiApp in conf.globalOptions: CC[cCompiler].buildGui
                    else: ""
     var exefile, builddll: string
-    if optGenDynLib in gGlobalOptions:
+    if optGenDynLib in conf.globalOptions:
       exefile = platform.OS[targetOS].dllFrmt % splitFile(projectfile).name
       builddll = CC[cCompiler].buildDll
     else:
       exefile = splitFile(projectfile).name & platform.OS[targetOS].exeExt
       builddll = ""
-    if options.outFile.len > 0:
-      exefile = options.outFile.expandTilde
+    if conf.outFile.len > 0:
+      exefile = conf.outFile.expandTilde
       if not exefile.isAbsolute():
         exefile = getCurrentDir() / exefile
-    if not noAbsolutePaths():
+    if not noAbsolutePaths(conf):
       if not exefile.isAbsolute():
         exefile = joinPath(splitFile(projectfile).dir, exefile)
     when false:
-      if optCDebug in gGlobalOptions:
+      if optCDebug in conf.globalOptions:
         writeDebugInfo(exefile.changeFileExt("ndb"))
     exefile = quoteShell(exefile)
-    let linkOptions = getLinkOptions() & " " &
-                      getConfigVar(cCompiler, ".options.linker")
-    var linkTmpl = getConfigVar(cCompiler, ".linkTmpl")
+    let linkOptions = getLinkOptions(conf) & " " &
+                      getConfigVar(conf, cCompiler, ".options.linker")
+    var linkTmpl = getConfigVar(conf, cCompiler, ".linkTmpl")
     if linkTmpl.len == 0:
       linkTmpl = CC[cCompiler].linkTmpl
     result = quoteShell(result % ["builddll", builddll,
         "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
-        "exefile", exefile, "nim", getPrefixDir(), "lib", libpath])
+        "exefile", exefile, "nim", getPrefixDir(conf), "lib", conf.libpath])
     result.add ' '
     addf(result, linkTmpl, ["builddll", builddll,
         "buildgui", buildgui, "options", linkOptions,
         "objfiles", objfiles, "exefile", exefile,
-        "nim", quoteShell(getPrefixDir()),
-        "lib", quoteShell(libpath)])
+        "nim", quoteShell(getPrefixDir(conf)),
+        "lib", quoteShell(conf.libpath)])
 
-template tryExceptOSErrorMessage(errorPrefix: string = "", body: untyped): typed =
+template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body: untyped): typed =
   try:
     body
   except OSError:
     let ose = (ref OSError)(getCurrentException())
     if errorPrefix.len > 0:
-      rawMessage(errGenerated, errorPrefix & " " & ose.msg & " " & $ose.errorCode)
+      rawMessage(conf, errGenerated, errorPrefix & " " & ose.msg & " " & $ose.errorCode)
     else:
-      rawMessage(errExecutionOfProgramFailed, ose.msg & " " & $ose.errorCode)
+      rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" %
+        (ose.msg & " " & $ose.errorCode))
     raise
 
-proc execLinkCmd(linkCmd: string) =
-  tryExceptOSErrorMessage("invocation of external linker program failed."):
-    execExternalProgram(linkCmd,
-      if optListCmd in gGlobalOptions or gVerbosity > 1: hintExecuting else: hintLinking)
+proc execLinkCmd(conf: ConfigRef; linkCmd: string) =
+  tryExceptOSErrorMessage(conf, "invocation of external linker program failed."):
+    execExternalProgram(conf, linkCmd,
+      if optListCmd in conf.globalOptions or conf.verbosity > 1: hintExecuting else: hintLinking)
 
-proc execCmdsInParallel(cmds: seq[string]; prettyCb: proc (idx: int)) =
+proc execCmdsInParallel(conf: ConfigRef; cmds: seq[string]; prettyCb: proc (idx: int)) =
   let runCb = proc (idx: int, p: Process) =
     let exitCode = p.peekExitCode
     if exitCode != 0:
-      rawMessage(errGenerated, "execution of an external compiler program '" &
+      rawMessage(conf, errGenerated, "execution of an external compiler program '" &
         cmds[idx] & "' failed with exit code: " & $exitCode & "\n\n" &
         p.outputStream.readAll.strip)
-  if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
+  if conf.numberOfProcessors == 0: conf.numberOfProcessors = countProcessors()
   var res = 0
-  if gNumberOfProcessors <= 1:
+  if conf.numberOfProcessors <= 1:
     for i in countup(0, high(cmds)):
-      tryExceptOSErrorMessage("invocation of external compiler program failed."):
-        res = execWithEcho(cmds[i])
-      if res != 0: rawMessage(errExecutionOfProgramFailed, cmds[i])
+      tryExceptOSErrorMessage(conf, "invocation of external compiler program failed."):
+        res = execWithEcho(conf, cmds[i])
+      if res != 0:
+        rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" %
+          cmds[i])
   else:
-    tryExceptOSErrorMessage("invocation of external compiler program failed."):
-      if optListCmd in gGlobalOptions or gVerbosity > 1:
+    tryExceptOSErrorMessage(conf, "invocation of external compiler program failed."):
+      if optListCmd in conf.globalOptions or conf.verbosity > 1:
         res = execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath},
-                            gNumberOfProcessors, afterRunEvent=runCb)
-      elif gVerbosity == 1:
+                            conf.numberOfProcessors, afterRunEvent=runCb)
+      elif conf.verbosity == 1:
         res = execProcesses(cmds, {poStdErrToStdOut, poUsePath},
-                            gNumberOfProcessors, prettyCb, afterRunEvent=runCb)
+                            conf.numberOfProcessors, prettyCb, afterRunEvent=runCb)
       else:
         res = execProcesses(cmds, {poStdErrToStdOut, poUsePath},
-                            gNumberOfProcessors, afterRunEvent=runCb)
+                            conf.numberOfProcessors, afterRunEvent=runCb)
   if res != 0:
-    if gNumberOfProcessors <= 1:
-      rawMessage(errExecutionOfProgramFailed, cmds.join())
+    if conf.numberOfProcessors <= 1:
+      rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" %
+        cmds.join())
 
-proc callCCompiler*(projectfile: string) =
+proc callCCompiler*(conf: ConfigRef; projectfile: string) =
   var
     linkCmd: string
-  if gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
+  if conf.globalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
     return # speed up that call if only compiling and no script shall be
            # generated
   #var c = cCompiler
@@ -758,36 +766,36 @@ proc callCCompiler*(projectfile: string) =
   var prettyCmds: TStringSeq = @[]
   let prettyCb = proc (idx: int) =
     echo prettyCmds[idx]
-  compileCFile(toCompile, script, cmds, prettyCmds)
-  if optCompileOnly notin gGlobalOptions:
-    execCmdsInParallel(cmds, prettyCb)
-  if optNoLinking notin gGlobalOptions:
+  compileCFile(conf, toCompile, script, cmds, prettyCmds)
+  if optCompileOnly notin conf.globalOptions:
+    execCmdsInParallel(conf, cmds, prettyCb)
+  if optNoLinking notin conf.globalOptions:
     # call the linker:
     var objfiles = ""
     for it in externalToLink:
-      let objFile = if noAbsolutePaths(): it.extractFilename else: it
+      let objFile = if noAbsolutePaths(conf): it.extractFilename else: it
       add(objfiles, ' ')
       add(objfiles, quoteShell(
           addFileExt(objFile, CC[cCompiler].objExt)))
     for x in toCompile:
-      let objFile = if noAbsolutePaths(): x.obj.extractFilename else: x.obj
+      let objFile = if noAbsolutePaths(conf): x.obj.extractFilename else: x.obj
       add(objfiles, ' ')
       add(objfiles, quoteShell(objFile))
 
-    linkCmd = getLinkCmd(projectfile, objfiles)
-    if optCompileOnly notin gGlobalOptions:
-      execLinkCmd(linkCmd)
+    linkCmd = getLinkCmd(conf, projectfile, objfiles)
+    if optCompileOnly notin conf.globalOptions:
+      execLinkCmd(conf, linkCmd)
   else:
     linkCmd = ""
-  if optGenScript in gGlobalOptions:
+  if optGenScript in conf.globalOptions:
     add(script, linkCmd)
     add(script, tnl)
-    generateScript(projectfile, script)
+    generateScript(conf, projectfile, script)
 
 #from json import escapeJson
 import json
 
-proc writeJsonBuildInstructions*(projectfile: string) =
+proc writeJsonBuildInstructions*(conf: ConfigRef; projectfile: string) =
   template lit(x: untyped) = f.write x
   template str(x: untyped) =
     when compiles(escapeJson(x, buf)):
@@ -797,11 +805,11 @@ proc writeJsonBuildInstructions*(projectfile: string) =
     else:
       f.write escapeJson(x)
 
-  proc cfiles(f: File; buf: var string; clist: CfileList, isExternal: bool) =
+  proc cfiles(conf: ConfigRef; f: File; buf: var string; clist: CfileList, isExternal: bool) =
     var pastStart = false
     for it in clist:
       if CfileFlag.Cached in it.flags: continue
-      let compileCmd = getCompileCFileCmd(it)
+      let compileCmd = getCompileCFileCmd(conf, it)
       if pastStart: lit "],\L"
       lit "["
       str it.cname
@@ -810,11 +818,11 @@ proc writeJsonBuildInstructions*(projectfile: string) =
       pastStart = true
     lit "]\L"
 
-  proc linkfiles(f: File; buf, objfiles: var string; clist: CfileList;
+  proc linkfiles(conf: ConfigRef; f: File; buf, objfiles: var string; clist: CfileList;
                  llist: seq[string]) =
     var pastStart = false
     for it in llist:
-      let objfile = if noAbsolutePaths(): it.extractFilename
+      let objfile = if noAbsolutePaths(conf): it.extractFilename
                     else: it
       let objstr = addFileExt(objfile, CC[cCompiler].objExt)
       add(objfiles, ' ')
@@ -835,25 +843,25 @@ proc writeJsonBuildInstructions*(projectfile: string) =
   var buf = newStringOfCap(50)
 
   let file = projectfile.splitFile.name
-  let jsonFile = toGeneratedFile(file, "json")
+  let jsonFile = toGeneratedFile(conf, file, "json")
 
   var f: File
   if open(f, jsonFile, fmWrite):
     lit "{\"compile\":[\L"
-    cfiles(f, buf, toCompile, false)
+    cfiles(conf, f, buf, toCompile, false)
     lit "],\L\"link\":[\L"
     var objfiles = ""
     # XXX add every file here that is to link
-    linkfiles(f, buf, objfiles, toCompile, externalToLink)
+    linkfiles(conf, f, buf, objfiles, toCompile, externalToLink)
 
     lit "],\L\"linkcmd\": "
-    str getLinkCmd(projectfile, objfiles)
+    str getLinkCmd(conf, projectfile, objfiles)
     lit "\L}\L"
     close(f)
 
-proc runJsonBuildInstructions*(projectfile: string) =
+proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: string) =
   let file = projectfile.splitFile.name
-  let jsonFile = toGeneratedFile(file, "json")
+  let jsonFile = toGeneratedFile(conf, file, "json")
   try:
     let data = json.parseFile(jsonFile)
     let toCompile = data["compile"]
@@ -870,32 +878,32 @@ proc runJsonBuildInstructions*(projectfile: string) =
 
     let prettyCb = proc (idx: int) =
       echo prettyCmds[idx]
-    execCmdsInParallel(cmds, prettyCb)
+    execCmdsInParallel(conf, cmds, prettyCb)
 
     let linkCmd = data["linkcmd"]
     doAssert linkCmd.kind == JString
-    execLinkCmd(linkCmd.getStr)
+    execLinkCmd(conf, linkCmd.getStr)
   except:
     echo getCurrentException().getStackTrace()
     quit "error evaluating JSON file: " & jsonFile
 
-proc genMappingFiles(list: CFileList): Rope =
+proc genMappingFiles(conf: ConfigRef; list: CFileList): Rope =
   for it in list:
     addf(result, "--file:r\"$1\"$N", [rope(it.cname)])
 
-proc writeMapping*(gSymbolMapping: Rope) =
-  if optGenMapping notin gGlobalOptions: return
+proc writeMapping*(conf: ConfigRef; symbolMapping: Rope) =
+  if optGenMapping notin conf.globalOptions: return
   var code = rope("[C_Files]\n")
-  add(code, genMappingFiles(toCompile))
+  add(code, genMappingFiles(conf, toCompile))
   add(code, "\n[C_Compiler]\nFlags=")
-  add(code, strutils.escape(getCompileOptions()))
+  add(code, strutils.escape(getCompileOptions(conf)))
 
   add(code, "\n[Linker]\nFlags=")
-  add(code, strutils.escape(getLinkOptions() & " " &
-                            getConfigVar(cCompiler, ".options.linker")))
+  add(code, strutils.escape(getLinkOptions(conf) & " " &
+                            getConfigVar(conf, cCompiler, ".options.linker")))
 
   add(code, "\n[Environment]\nlibpath=")
-  add(code, strutils.escape(libpath))
+  add(code, strutils.escape(conf.libpath))
 
-  addf(code, "\n[Symbols]$n$1", [gSymbolMapping])
-  writeRope(code, joinPath(gProjectPath, "mapping.txt"))
+  addf(code, "\n[Symbols]$n$1", [symbolMapping])
+  writeRope(code, joinPath(conf.projectPath, "mapping.txt"))
diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim
index 545bea950..f93355e6b 100644
--- a/compiler/filter_tmpl.nim
+++ b/compiler/filter_tmpl.nim
@@ -27,7 +27,7 @@ type
     emit, conc, toStr: string
     curly, bracket, par: int
     pendingExprLine: bool
-
+    config: ConfigRef
 
 const
   PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '.', '_'}
@@ -70,9 +70,9 @@ proc parseLine(p: var TTmplParser) =
 
   while j <= hi and p.x[j] == ' ': inc(j)
 
-  if p.x[0] == p.nimDirective and p.x[1] == '?':
+  if p.x.len >= 2 and p.x[0] == p.nimDirective and p.x[1] == '?':
     newLine(p)
-  elif p.x[j] == p.nimDirective:
+  elif j < p.x.len and p.x[j] == p.nimDirective:
     newLine(p)
     inc(j)
     while j <= hi and p.x[j] == ' ': inc(j)
@@ -90,7 +90,7 @@ proc parseLine(p: var TTmplParser) =
         dec(p.indent, 2)
       else:
         p.info.col = int16(j)
-        localError(p.info, errXNotAllowedHere, "end")
+        localError(p.config, p.info, "'end' does not close a control flow construct")
       llStreamWrite(p.outp, spaces(p.indent))
       llStreamWrite(p.outp, "#end")
     of "if", "when", "try", "while", "for", "block", "case", "proc", "iterator",
@@ -175,7 +175,7 @@ proc parseLine(p: var TTmplParser) =
                 llStreamWrite(p.outp, p.x[j])
                 inc(j)
             if curly > 0:
-              localError(p.info, errXExpected, "}")
+              localError(p.config, p.info, "expected closing '}'")
               break
             llStreamWrite(p.outp, ')')
             llStreamWrite(p.outp, p.conc)
@@ -197,22 +197,23 @@ proc parseLine(p: var TTmplParser) =
               inc(j)
             else:
               p.info.col = int16(j)
-              localError(p.info, errInvalidExpression, "$")
+              localError(p.config, p.info, "invalid expression")
         else:
           llStreamWrite(p.outp, p.x[j])
           inc(j)
     llStreamWrite(p.outp, "\\n\"")
 
-proc filterTmpl*(stdin: PLLStream, filename: string, call: PNode): PLLStream =
+proc filterTmpl*(stdin: PLLStream, filename: string, call: PNode; conf: ConfigRef): PLLStream =
   var p: TTmplParser
-  p.info = newLineInfo(filename, 0, 0)
+  p.config = conf
+  p.info = newLineInfo(conf, filename, 0, 0)
   p.outp = llStreamOpen("")
   p.inp = stdin
-  p.subsChar = charArg(call, "subschar", 1, '$')
-  p.nimDirective = charArg(call, "metachar", 2, '#')
-  p.emit = strArg(call, "emit", 3, "result.add")
-  p.conc = strArg(call, "conc", 4, " & ")
-  p.toStr = strArg(call, "tostring", 5, "$")
+  p.subsChar = charArg(conf, call, "subschar", 1, '$')
+  p.nimDirective = charArg(conf, call, "metachar", 2, '#')
+  p.emit = strArg(conf, call, "emit", 3, "result.add")
+  p.conc = strArg(conf, call, "conc", 4, " & ")
+  p.toStr = strArg(conf, call, "tostring", 5, "$")
   p.x = newStringOfCap(120)
   # do not process the first line which contains the directive:
   if llStreamReadLine(p.inp, p.x):
diff --git a/compiler/filters.nim b/compiler/filters.nim
index 37df628ed..3ebbad678 100644
--- a/compiler/filters.nim
+++ b/compiler/filters.nim
@@ -13,43 +13,44 @@ import
   llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
   renderer
 
-proc invalidPragma(n: PNode) =
-  localError(n.info, errXNotAllowedHere, renderTree(n, {renderNoComments}))
+proc invalidPragma(conf: ConfigRef; n: PNode) =
+  localError(conf, n.info,
+      "'$1' not allowed here" % renderTree(n, {renderNoComments}))
 
-proc getArg(n: PNode, name: string, pos: int): PNode =
+proc getArg(conf: ConfigRef; n: PNode, name: string, pos: int): PNode =
   result = nil
   if n.kind in {nkEmpty..nkNilLit}: return
   for i in countup(1, sonsLen(n) - 1):
     if n.sons[i].kind == nkExprEqExpr:
-      if n.sons[i].sons[0].kind != nkIdent: invalidPragma(n)
+      if n.sons[i].sons[0].kind != nkIdent: invalidPragma(conf, n)
       if cmpIgnoreStyle(n.sons[i].sons[0].ident.s, name) == 0:
         return n.sons[i].sons[1]
     elif i == pos:
       return n.sons[i]
 
-proc charArg*(n: PNode, name: string, pos: int, default: char): char =
-  var x = getArg(n, name, pos)
+proc charArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: char): char =
+  var x = getArg(conf, n, name, pos)
   if x == nil: result = default
   elif x.kind == nkCharLit: result = chr(int(x.intVal))
-  else: invalidPragma(n)
+  else: invalidPragma(conf, n)
 
-proc strArg*(n: PNode, name: string, pos: int, default: string): string =
-  var x = getArg(n, name, pos)
+proc strArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: string): string =
+  var x = getArg(conf, n, name, pos)
   if x == nil: result = default
   elif x.kind in {nkStrLit..nkTripleStrLit}: result = x.strVal
-  else: invalidPragma(n)
+  else: invalidPragma(conf, n)
 
-proc boolArg*(n: PNode, name: string, pos: int, default: bool): bool =
-  var x = getArg(n, name, pos)
+proc boolArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: bool): bool =
+  var x = getArg(conf, n, name, pos)
   if x == nil: result = default
   elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "true") == 0: result = true
   elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "false") == 0: result = false
-  else: invalidPragma(n)
+  else: invalidPragma(conf, n)
 
-proc filterStrip*(stdin: PLLStream, filename: string, call: PNode): PLLStream =
-  var pattern = strArg(call, "startswith", 1, "")
-  var leading = boolArg(call, "leading", 2, true)
-  var trailing = boolArg(call, "trailing", 3, true)
+proc filterStrip*(conf: ConfigRef; stdin: PLLStream, filename: string, call: PNode): PLLStream =
+  var pattern = strArg(conf, call, "startswith", 1, "")
+  var leading = boolArg(conf, call, "leading", 2, true)
+  var trailing = boolArg(conf, call, "trailing", 3, true)
   result = llStreamOpen("")
   var line = newStringOfCap(80)
   while llStreamReadLine(stdin, line):
@@ -60,10 +61,10 @@ proc filterStrip*(stdin: PLLStream, filename: string, call: PNode): PLLStream =
       llStreamWriteln(result, line)
   llStreamClose(stdin)
 
-proc filterReplace*(stdin: PLLStream, filename: string, call: PNode): PLLStream =
-  var sub = strArg(call, "sub", 1, "")
-  if len(sub) == 0: invalidPragma(call)
-  var by = strArg(call, "by", 2, "")
+proc filterReplace*(conf: ConfigRef; stdin: PLLStream, filename: string, call: PNode): PLLStream =
+  var sub = strArg(conf, call, "sub", 1, "")
+  if len(sub) == 0: invalidPragma(conf, call)
+  var by = strArg(conf, call, "by", 2, "")
   result = llStreamOpen("")
   var line = newStringOfCap(80)
   while llStreamReadLine(stdin, line):
diff --git a/compiler/gorgeimpl.nim b/compiler/gorgeimpl.nim
index 80302b4b5..44c7651bc 100644
--- a/compiler/gorgeimpl.nim
+++ b/compiler/gorgeimpl.nim
@@ -21,11 +21,11 @@ proc readOutput(p: Process): (string, int) =
     result[0].setLen(result[0].len - "\n".len)
   result[1] = p.waitForExit
 
-proc opGorge*(cmd, input, cache: string, info: TLineInfo): (string, int) =
+proc opGorge*(cmd, input, cache: string, info: TLineInfo; conf: ConfigRef): (string, int) =
   let workingDir = parentDir(info.toFullPath)
   if cache.len > 0:# and optForceFullMake notin gGlobalOptions:
     let h = secureHash(cmd & "\t" & input & "\t" & cache)
-    let filename = options.toGeneratedFile("gorge_" & $h, "txt")
+    let filename = options.toGeneratedFile(conf, "gorge_" & $h, "txt")
     var f: File
     if open(f, filename):
       result = (f.readAll, 0)
diff --git a/compiler/guards.nim b/compiler/guards.nim
index 94af5202d..d39ea799b 100644
--- a/compiler/guards.nim
+++ b/compiler/guards.nim
@@ -10,7 +10,7 @@
 ## This module implements the 'implies' relation for guards.
 
 import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents,
-  saturate
+  saturate, modulegraphs, options, configuration
 
 const
   someEq = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
@@ -83,18 +83,25 @@ proc isLetLocation(m: PNode, isApprox: bool): bool =
 
 proc interestingCaseExpr*(m: PNode): bool = isLetLocation(m, true)
 
-let
-  opLe = createMagic("<=", mLeI)
-  opLt = createMagic("<", mLtI)
-  opAnd = createMagic("and", mAnd)
-  opOr = createMagic("or", mOr)
-  opIsNil = createMagic("isnil", mIsNil)
-  opEq = createMagic("==", mEqI)
-  opAdd = createMagic("+", mAddI)
-  opSub = createMagic("-", mSubI)
-  opMul = createMagic("*", mMulI)
-  opDiv = createMagic("div", mDivI)
-  opLen = createMagic("len", mLengthSeq)
+type
+  Operators* = object
+    opNot, opContains, opLe, opLt, opAnd, opOr, opIsNil, opEq: PSym
+    opAdd, opSub, opMul, opDiv, opLen: PSym
+
+proc initOperators*(g: ModuleGraph): Operators =
+  result.opLe = createMagic(g, "<=", mLeI)
+  result.opLt = createMagic(g, "<", mLtI)
+  result.opAnd = createMagic(g, "and", mAnd)
+  result.opOr = createMagic(g, "or", mOr)
+  result.opIsNil = createMagic(g, "isnil", mIsNil)
+  result.opEq = createMagic(g, "==", mEqI)
+  result.opAdd = createMagic(g, "+", mAddI)
+  result.opSub = createMagic(g, "-", mSubI)
+  result.opMul = createMagic(g, "*", mMulI)
+  result.opDiv = createMagic(g, "div", mDivI)
+  result.opLen = createMagic(g, "len", mLengthSeq)
+  result.opNot = createMagic(g, "not", mNot)
+  result.opContains = createMagic(g, "contains", mInSet)
 
 proc swapArgs(fact: PNode, newOp: PSym): PNode =
   result = newNodeI(nkCall, fact.info, 3)
@@ -102,16 +109,16 @@ proc swapArgs(fact: PNode, newOp: PSym): PNode =
   result.sons[1] = fact.sons[2]
   result.sons[2] = fact.sons[1]
 
-proc neg(n: PNode): PNode =
+proc neg(n: PNode; o: Operators): PNode =
   if n == nil: return nil
   case n.getMagic
   of mNot:
     result = n.sons[1]
   of someLt:
     # not (a < b)  ==  a >= b  ==  b <= a
-    result = swapArgs(n, opLe)
+    result = swapArgs(n, o.opLe)
   of someLe:
-    result = swapArgs(n, opLt)
+    result = swapArgs(n, o.opLt)
   of mInSet:
     if n.sons[1].kind != nkCurly: return nil
     let t = n.sons[2].typ.skipTypes(abstractInst)
@@ -133,11 +140,11 @@ proc neg(n: PNode): PNode =
   of mOr:
     # not (a or b) --> not a and not b
     let
-      a = n.sons[1].neg
-      b = n.sons[2].neg
+      a = n.sons[1].neg(o)
+      b = n.sons[2].neg(o)
     if a != nil and b != nil:
       result = newNodeI(nkCall, n.info, 3)
-      result.sons[0] = newSymNode(opAnd)
+      result.sons[0] = newSymNode(o.opAnd)
       result.sons[1] = a
       result.sons[2] = b
     elif a != nil:
@@ -147,7 +154,7 @@ proc neg(n: PNode): PNode =
   else:
     # leave  not (a == 4)  as it is
     result = newNodeI(nkCall, n.info, 2)
-    result.sons[0] = newSymNode(opNot)
+    result.sons[0] = newSymNode(o.opNot)
     result.sons[1] = n
 
 proc buildCall(op: PSym; a: PNode): PNode =
@@ -181,7 +188,7 @@ proc `|div|`(a, b: PNode): PNode =
   if a.kind in {nkCharLit..nkUInt64Lit}: result.intVal = a.intVal div b.intVal
   else: result.floatVal = a.floatVal / b.floatVal
 
-proc negate(a, b, res: PNode): PNode =
+proc negate(a, b, res: PNode; o: Operators): PNode =
   if b.kind in {nkCharLit..nkUInt64Lit} and b.intVal != low(BiggestInt):
     var b = copyNode(b)
     b.intVal = -b.intVal
@@ -189,11 +196,11 @@ proc negate(a, b, res: PNode): PNode =
       b.intVal = b.intVal |+| a.intVal
       result = b
     else:
-      result = buildCall(opAdd, a, b)
+      result = buildCall(o.opAdd, a, b)
   elif b.kind in {nkFloatLit..nkFloat64Lit}:
     var b = copyNode(b)
     b.floatVal = -b.floatVal
-    result = buildCall(opAdd, a, b)
+    result = buildCall(o.opAdd, a, b)
   else:
     result = res
 
@@ -205,7 +212,7 @@ proc lowBound*(x: PNode): PNode =
   result = nkIntLit.newIntNode(firstOrd(x.typ))
   result.info = x.info
 
-proc highBound*(x: PNode): PNode =
+proc highBound*(x: PNode; o: Operators): PNode =
   let typ = x.typ.skipTypes(abstractInst)
   result = if typ.kind == tyArray:
              nkIntLit.newIntNode(lastOrd(typ))
@@ -213,23 +220,23 @@ proc highBound*(x: PNode): PNode =
                x.sym.kind == skConst:
              nkIntLit.newIntNode(x.sym.ast.len-1)
            else:
-             opAdd.buildCall(opLen.buildCall(x), minusOne())
+             o.opAdd.buildCall(o.opLen.buildCall(x), minusOne())
   result.info = x.info
 
-proc reassociation(n: PNode): PNode =
+proc reassociation(n: PNode; o: Operators): PNode =
   result = n
   # (foo+5)+5 --> foo+10;  same for '*'
   case result.getMagic
   of someAdd:
     if result[2].isValue and
         result[1].getMagic in someAdd and result[1][2].isValue:
-      result = opAdd.buildCall(result[1][1], result[1][2] |+| result[2])
+      result = o.opAdd.buildCall(result[1][1], result[1][2] |+| result[2])
       if result[2].intVal == 0:
         result = result[1]
   of someMul:
     if result[2].isValue and
         result[1].getMagic in someMul and result[1][2].isValue:
-      result = opMul.buildCall(result[1][1], result[1][2] |*| result[2])
+      result = o.opMul.buildCall(result[1][1], result[1][2] |*| result[2])
       if result[2].intVal == 1:
         result = result[1]
       elif result[2].intVal == 0:
@@ -243,12 +250,12 @@ proc pred(n: PNode): PNode =
   else:
     result = n
 
-proc canon*(n: PNode): PNode =
+proc canon*(n: PNode; o: Operators): PNode =
   # XXX for now only the new code in 'semparallel' uses this
   if n.safeLen >= 1:
     result = shallowCopy(n)
     for i in 0 ..< n.len:
-      result.sons[i] = canon(n.sons[i])
+      result.sons[i] = canon(n.sons[i], o)
   elif n.kind == nkSym and n.sym.kind == skLet and
       n.sym.ast.getMagic in (someEq + someAdd + someMul + someMin +
       someMax + someHigh + {mUnaryLt} + someSub + someLen + someDiv):
@@ -263,24 +270,24 @@ proc canon*(n: PNode): PNode =
       # (4 + foo) + 2 --> (foo + 4) + 2
   of someHigh:
     # high == len+(-1)
-    result = opAdd.buildCall(opLen.buildCall(result[1]), minusOne())
+    result = o.opAdd.buildCall(o.opLen.buildCall(result[1]), minusOne())
   of mUnaryLt:
-    result = buildCall(opAdd, result[1], minusOne())
+    result = buildCall(o.opAdd, result[1], minusOne())
   of someSub:
     # x - 4  -->  x + (-4)
-    result = negate(result[1], result[2], result)
+    result = negate(result[1], result[2], result, o)
   of someLen:
-    result.sons[0] = opLen.newSymNode
+    result.sons[0] = o.opLen.newSymNode
   of someLt:
     # x < y  same as x <= y-1:
-    let y = n[2].canon
+    let y = n[2].canon(o)
     let p = pred(y)
-    let minus = if p != y: p else: opAdd.buildCall(y, minusOne()).canon
-    result = opLe.buildCall(n[1].canon, minus)
+    let minus = if p != y: p else: o.opAdd.buildCall(y, minusOne()).canon(o)
+    result = o.opLe.buildCall(n[1].canon(o), minus)
   else: discard
 
   result = skipConv(result)
-  result = reassociation(result)
+  result = reassociation(result, o)
   # most important rule: (x-4) <= a.len -->  x <= a.len+4
   case result.getMagic
   of someLe:
@@ -291,10 +298,10 @@ proc canon*(n: PNode): PNode =
       case x.getMagic
       of someSub:
         result = buildCall(result[0].sym, x[1],
-                           reassociation(opAdd.buildCall(y, x[2])))
+                           reassociation(o.opAdd.buildCall(y, x[2]), o))
       of someAdd:
         # Rule A:
-        let plus = negate(y, x[2], nil).reassociation
+        let plus = negate(y, x[2], nil, o).reassociation(o)
         if plus != nil: result = buildCall(result[0].sym, x[1], plus)
       else: discard
     elif y.kind in nkCallKinds and y.len == 3 and y[2].isValue and
@@ -303,9 +310,9 @@ proc canon*(n: PNode): PNode =
       case y.getMagic
       of someSub:
         result = buildCall(result[0].sym, y[1],
-                           reassociation(opAdd.buildCall(x, y[2])))
+                           reassociation(o.opAdd.buildCall(x, y[2]), o))
       of someAdd:
-        let plus = negate(x, y[2], nil).reassociation
+        let plus = negate(x, y[2], nil, o).reassociation(o)
         # ensure that Rule A will not trigger afterwards with the
         # additional 'not isLetLocation' constraint:
         if plus != nil and not isLetLocation(x, true):
@@ -323,15 +330,15 @@ proc canon*(n: PNode): PNode =
       result.sons[2] = y[1]
   else: discard
 
-proc `+@`*(a: PNode; b: BiggestInt): PNode =
-  canon(if b != 0: opAdd.buildCall(a, nkIntLit.newIntNode(b)) else: a)
+proc buildAdd*(a: PNode; b: BiggestInt; o: Operators): PNode =
+  canon(if b != 0: o.opAdd.buildCall(a, nkIntLit.newIntNode(b)) else: a, o)
 
-proc usefulFact(n: PNode): PNode =
+proc usefulFact(n: PNode; o: Operators): PNode =
   case n.getMagic
   of someEq:
     if skipConv(n.sons[2]).kind == nkNilLit and (
         isLetLocation(n.sons[1], false) or isVar(n.sons[1])):
-      result = opIsNil.buildCall(n.sons[1])
+      result = o.opIsNil.buildCall(n.sons[1])
     else:
       if isLetLocation(n.sons[1], true) or isLetLocation(n.sons[2], true):
         # XXX algebraic simplifications!  'i-1 < a.len' --> 'i < a.len+1'
@@ -351,11 +358,11 @@ proc usefulFact(n: PNode): PNode =
       result = n
   of mAnd:
     let
-      a = usefulFact(n.sons[1])
-      b = usefulFact(n.sons[2])
+      a = usefulFact(n.sons[1], o)
+      b = usefulFact(n.sons[2], o)
     if a != nil and b != nil:
       result = newNodeI(nkCall, n.info, 3)
-      result.sons[0] = newSymNode(opAnd)
+      result.sons[0] = newSymNode(o.opAnd)
       result.sons[1] = a
       result.sons[2] = b
     elif a != nil:
@@ -363,9 +370,9 @@ proc usefulFact(n: PNode): PNode =
     elif b != nil:
       result = b
   of mNot:
-    let a = usefulFact(n.sons[1])
+    let a = usefulFact(n.sons[1], o)
     if a != nil:
-      result = a.neg
+      result = a.neg(o)
   of mOr:
     # 'or' sucks! (p.isNil or q.isNil) --> hard to do anything
     # with that knowledge...
@@ -374,14 +381,14 @@ proc usefulFact(n: PNode): PNode =
     #  (x == 3) or (y == 2)  ---> not ( not (x==3) and not (y == 2))
     #  not (x != 3 and y != 2)
     let
-      a = usefulFact(n.sons[1]).neg
-      b = usefulFact(n.sons[2]).neg
+      a = usefulFact(n.sons[1], o).neg(o)
+      b = usefulFact(n.sons[2], o).neg(o)
     if a != nil and b != nil:
       result = newNodeI(nkCall, n.info, 3)
-      result.sons[0] = newSymNode(opAnd)
+      result.sons[0] = newSymNode(o.opAnd)
       result.sons[1] = a
       result.sons[2] = b
-      result = result.neg
+      result = result.neg(o)
   elif n.kind == nkSym and n.sym.kind == skLet:
     # consider:
     #   let a = 2 < x
@@ -389,32 +396,34 @@ proc usefulFact(n: PNode): PNode =
     #     ...
     # We make can easily replace 'a' by '2 < x' here:
     if n.sym.ast != nil:
-      result = usefulFact(n.sym.ast)
+      result = usefulFact(n.sym.ast, o)
   elif n.kind == nkStmtListExpr:
-    result = usefulFact(n.lastSon)
+    result = usefulFact(n.lastSon, o)
 
 type
-  TModel* = seq[PNode] # the "knowledge base"
+  TModel* = object
+    s*: seq[PNode] # the "knowledge base"
+    o*: Operators
 
 proc addFact*(m: var TModel, nn: PNode) =
-  let n = usefulFact(nn)
-  if n != nil: m.add n
+  let n = usefulFact(nn, m.o)
+  if n != nil: m.s.add n
 
 proc addFactNeg*(m: var TModel, n: PNode) =
-  let n = n.neg
+  let n = n.neg(m.o)
   if n != nil: addFact(m, n)
 
-proc canonOpr(opr: PSym): PSym =
-  case opr.magic
-  of someEq: result = opEq
-  of someLe: result = opLe
-  of someLt: result = opLt
-  of someLen: result = opLen
-  of someAdd: result = opAdd
-  of someSub: result = opSub
-  of someMul: result = opMul
-  of someDiv: result = opDiv
-  else: result = opr
+proc sameOpr(a, b: PSym): bool =
+  case a.magic
+  of someEq: result = b.magic in someEq
+  of someLe: result = b.magic in someLe
+  of someLt: result = b.magic in someLt
+  of someLen: result = b.magic in someLen
+  of someAdd: result = b.magic in someAdd
+  of someSub: result = b.magic in someSub
+  of someMul: result = b.magic in someMul
+  of someDiv: result = b.magic in someDiv
+  else: result = a == b
 
 proc sameTree*(a, b: PNode): bool =
   result = false
@@ -425,7 +434,7 @@ proc sameTree*(a, b: PNode): bool =
     of nkSym:
       result = a.sym == b.sym
       if not result and a.sym.magic != mNone:
-        result = a.sym.magic == b.sym.magic or canonOpr(a.sym) == canonOpr(b.sym)
+        result = a.sym.magic == b.sym.magic or sameOpr(a.sym, b.sym)
     of nkIdent: result = a.ident.id == b.ident.id
     of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
     of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
@@ -462,8 +471,8 @@ proc invalidateFacts*(m: var TModel, n: PNode) =
   # The same mechanism could be used for more complex data stored on the heap;
   # procs that 'write: []' cannot invalidate 'n.kind' for instance. In fact, we
   # could CSE these expressions then and help C's optimizer.
-  for i in 0..high(m):
-    if m[i] != nil and m[i].hasSubTree(n): m[i] = nil
+  for i in 0..high(m.s):
+    if m.s[i] != nil and m.s[i].hasSubTree(n): m.s[i] = nil
 
 proc valuesUnequal(a, b: PNode): bool =
   if a.isValue and b.isValue:
@@ -486,7 +495,7 @@ proc impliesEq(fact, eq: PNode): TImplication =
     if sameTree(fact.sons[2], eq.sons[loc]) and isValue(eq.sons[val]):
       if inSet(fact.sons[1], eq.sons[val]): result = impYes
       else: result = impNo
-  of mNot, mOr, mAnd: internalError(eq.info, "impliesEq")
+  of mNot, mOr, mAnd: assert(false, "impliesEq")
   else: discard
 
 proc leImpliesIn(x, c, aSet: PNode): TImplication =
@@ -549,7 +558,7 @@ proc impliesIn(fact, loc, aSet: PNode): TImplication =
     elif sameTree(fact.sons[2], loc):
       # 4 < x  -->  3 <= x
       result = geImpliesIn(fact.sons[2], fact.sons[1].pred, aSet)
-  of mNot, mOr, mAnd: internalError(loc.info, "impliesIn")
+  of mNot, mOr, mAnd: assert(false, "impliesIn")
   else: discard
 
 proc valueIsNil(n: PNode): TImplication =
@@ -567,11 +576,11 @@ proc impliesIsNil(fact, eq: PNode): TImplication =
       result = valueIsNil(fact.sons[2].skipConv)
     elif sameTree(fact.sons[2], eq.sons[1]):
       result = valueIsNil(fact.sons[1].skipConv)
-  of mNot, mOr, mAnd: internalError(eq.info, "impliesIsNil")
+  of mNot, mOr, mAnd: assert(false, "impliesIsNil")
   else: discard
 
 proc impliesGe(fact, x, c: PNode): TImplication =
-  internalAssert isLocation(x)
+  assert isLocation(x)
   case fact.sons[0].sym.magic
   of someEq:
     if sameTree(fact.sons[1], x):
@@ -603,7 +612,7 @@ proc impliesGe(fact, x, c: PNode): TImplication =
       # fact: 3 <= x; question: x >= 2 ?  --> true iff 2 <= 3
       if isValue(fact.sons[1]) and isValue(c):
         if leValue(c, fact.sons[1]): result = impYes
-  of mNot, mOr, mAnd: internalError(x.info, "impliesGe")
+  of mNot, mOr, mAnd: assert(false, "impliesGe")
   else: discard
 
 proc impliesLe(fact, x, c: PNode): TImplication =
@@ -643,7 +652,7 @@ proc impliesLe(fact, x, c: PNode): TImplication =
       if isValue(fact.sons[1]) and isValue(c):
         if leValue(c, fact.sons[1].pred): result = impNo
 
-  of mNot, mOr, mAnd: internalError(x.info, "impliesLe")
+  of mNot, mOr, mAnd: assert(false, "impliesLe")
   else: discard
 
 proc impliesLt(fact, x, c: PNode): TImplication =
@@ -707,14 +716,14 @@ proc factImplies(fact, prop: PNode): TImplication =
 
 proc doesImply*(facts: TModel, prop: PNode): TImplication =
   assert prop.kind in nkCallKinds
-  for f in facts:
+  for f in facts.s:
     # facts can be invalidated, in which case they are 'nil':
     if not f.isNil:
       result = f.factImplies(prop)
       if result != impUnknown: return
 
-proc impliesNotNil*(facts: TModel, arg: PNode): TImplication =
-  result = doesImply(facts, opIsNil.buildCall(arg).neg)
+proc impliesNotNil*(m: TModel, arg: PNode): TImplication =
+  result = doesImply(m, m.o.opIsNil.buildCall(arg).neg(m.o))
 
 proc simpleSlice*(a, b: PNode): BiggestInt =
   # returns 'c' if a..b matches (i+c)..(i+c), -1 otherwise. (i)..(i) is matched
@@ -817,20 +826,20 @@ proc ple(m: TModel; a, b: PNode): TImplication =
   if a.getMagic in someMul and a[2].isValue and a[1].getMagic in someDiv and
       a[1][2].isValue:
     # simplify   (x div 4) * 2 <= y   to  x div (c div d)  <= y
-    if ple(m, buildCall(opDiv, a[1][1], `|div|`(a[1][2], a[2])), b) == impYes:
+    if ple(m, buildCall(m.o.opDiv, a[1][1], `|div|`(a[1][2], a[2])), b) == impYes:
       return impYes
 
   # x*3 + x == x*4. It follows that:
   # x*3 + y <= x*4  if  y <= x  and 3 <= 4
   if a =~ x*dc + y and b =~ x2*ec:
     if sameTree(x, x2):
-      let ec1 = opAdd.buildCall(ec, minusOne())
+      let ec1 = m.o.opAdd.buildCall(ec, minusOne())
       if x >=? 1 and ec >=? 1 and dc >=? 1 and dc <=? ec1 and y <=? x:
         return impYes
   elif a =~ x*dc and b =~ x2*ec + y:
     #echo "BUG cam ehrer e ", a, " <=? ", b
     if sameTree(x, x2):
-      let ec1 = opAdd.buildCall(ec, minusOne())
+      let ec1 = m.o.opAdd.buildCall(ec, minusOne())
       if x >=? 1 and ec >=? 1 and dc >=? 1 and dc <=? ec1 and y <=? zero():
         return impYes
 
@@ -863,9 +872,9 @@ proc ple(m: TModel; a, b: PNode): TImplication =
 
   # use the knowledge base:
   return pleViaModel(m, a, b)
-  #return doesImply(m, opLe.buildCall(a, b))
+  #return doesImply(m, o.opLe.buildCall(a, b))
 
-type TReplacements = seq[tuple[a,b: PNode]]
+type TReplacements = seq[tuple[a, b: PNode]]
 
 proc replaceSubTree(n, x, by: PNode): PNode =
   if sameTree(n, x):
@@ -883,11 +892,11 @@ proc applyReplacements(n: PNode; rep: TReplacements): PNode =
 
 proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication =
   # now check for inferrable facts: a <= b and b <= c  implies a <= c
-  for i in 0..m.high:
-    let fact = m[i]
+  for i in 0..m.s.high:
+    let fact = m.s[i]
     if fact != nil and fact.getMagic in someLe:
       # mark as used:
-      m[i] = nil
+      m.s[i] = nil
       # i <= len-100
       # i <=? len-1
       # --> true  if  (len-100) <= (len-1)
@@ -919,7 +928,7 @@ proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication =
 proc pleViaModel(model: TModel; aa, bb: PNode): TImplication =
   # compute replacements:
   var replacements: TReplacements = @[]
-  for fact in model:
+  for fact in model.s:
     if fact != nil and fact.getMagic in someEq:
       let a = fact[1]
       let b = fact[2]
@@ -929,12 +938,13 @@ proc pleViaModel(model: TModel; aa, bb: PNode): TImplication =
   var a = aa
   var b = bb
   if replacements.len > 0:
-    m = @[]
+    m.s = @[]
+    m.o = model.o
     # make the other facts consistent:
-    for fact in model:
+    for fact in model.s:
       if fact != nil and fact.getMagic notin someEq:
         # XXX 'canon' should not be necessary here, but it is
-        m.add applyReplacements(fact, replacements).canon
+        m.s.add applyReplacements(fact, replacements).canon(m.o)
     a = applyReplacements(aa, replacements)
     b = applyReplacements(bb, replacements)
   else:
@@ -943,31 +953,31 @@ proc pleViaModel(model: TModel; aa, bb: PNode): TImplication =
   result = pleViaModelRec(m, a, b)
 
 proc proveLe*(m: TModel; a, b: PNode): TImplication =
-  let x = canon(opLe.buildCall(a, b))
+  let x = canon(m.o.opLe.buildCall(a, b), m.o)
   #echo "ROOT ", renderTree(x[1]), " <=? ", renderTree(x[2])
   result = ple(m, x[1], x[2])
   if result == impUnknown:
     # try an alternative:  a <= b  iff  not (b < a)  iff  not (b+1 <= a):
-    let y = canon(opLe.buildCall(opAdd.buildCall(b, one()), a))
+    let y = canon(m.o.opLe.buildCall(m.o.opAdd.buildCall(b, one()), a), m.o)
     result = ~ple(m, y[1], y[2])
 
 proc addFactLe*(m: var TModel; a, b: PNode) =
-  m.add canon(opLe.buildCall(a, b))
+  m.s.add canon(m.o.opLe.buildCall(a, b), m.o)
 
 proc settype(n: PNode): PType =
   result = newType(tySet, n.typ.owner)
   addSonSkipIntLit(result, n.typ)
 
-proc buildOf(it, loc: PNode): PNode =
+proc buildOf(it, loc: PNode; o: Operators): PNode =
   var s = newNodeI(nkCurly, it.info, it.len-1)
   s.typ = settype(loc)
   for i in 0..it.len-2: s.sons[i] = it.sons[i]
   result = newNodeI(nkCall, it.info, 3)
-  result.sons[0] = newSymNode(opContains)
+  result.sons[0] = newSymNode(o.opContains)
   result.sons[1] = s
   result.sons[2] = loc
 
-proc buildElse(n: PNode): PNode =
+proc buildElse(n: PNode; o: Operators): PNode =
   var s = newNodeIT(nkCurly, n.info, settype(n.sons[0]))
   for i in 1..n.len-2:
     let branch = n.sons[i]
@@ -975,23 +985,23 @@ proc buildElse(n: PNode): PNode =
     for j in 0..branch.len-2:
       s.add(branch.sons[j])
   result = newNodeI(nkCall, n.info, 3)
-  result.sons[0] = newSymNode(opContains)
+  result.sons[0] = newSymNode(o.opContains)
   result.sons[1] = s
   result.sons[2] = n.sons[0]
 
 proc addDiscriminantFact*(m: var TModel, n: PNode) =
   var fact = newNodeI(nkCall, n.info, 3)
-  fact.sons[0] = newSymNode(opEq)
+  fact.sons[0] = newSymNode(m.o.opEq)
   fact.sons[1] = n.sons[0]
   fact.sons[2] = n.sons[1]
-  m.add fact
+  m.s.add fact
 
 proc addAsgnFact*(m: var TModel, key, value: PNode) =
   var fact = newNodeI(nkCall, key.info, 3)
-  fact.sons[0] = newSymNode(opEq)
+  fact.sons[0] = newSymNode(m.o.opEq)
   fact.sons[1] = key
   fact.sons[2] = value
-  m.add fact
+  m.s.add fact
 
 proc sameSubexprs*(m: TModel; a, b: PNode): bool =
   # This should be used to check whether two *path expressions* refer to the
@@ -1004,7 +1014,7 @@ proc sameSubexprs*(m: TModel; a, b: PNode): bool =
   # However, nil checking requires exactly the same mechanism! But for now
   # we simply use sameTree and live with the unsoundness of the analysis.
   var check = newNodeI(nkCall, a.info, 3)
-  check.sons[0] = newSymNode(opEq)
+  check.sons[0] = newSymNode(m.o.opEq)
   check.sons[1] = a
   check.sons[2] = b
   result = m.doesImply(check) == impYes
@@ -1012,11 +1022,11 @@ proc sameSubexprs*(m: TModel; a, b: PNode): bool =
 proc addCaseBranchFacts*(m: var TModel, n: PNode, i: int) =
   let branch = n.sons[i]
   if branch.kind == nkOfBranch:
-    m.add buildOf(branch, n.sons[0])
+    m.s.add buildOf(branch, n.sons[0], m.o)
   else:
-    m.add n.buildElse.neg
+    m.s.add n.buildElse(m.o).neg(m.o)
 
-proc buildProperFieldCheck(access, check: PNode): PNode =
+proc buildProperFieldCheck(access, check: PNode; o: Operators): PNode =
   if check.sons[1].kind == nkCurly:
     result = copyTree(check)
     if access.kind == nkDotExpr:
@@ -1028,10 +1038,10 @@ proc buildProperFieldCheck(access, check: PNode): PNode =
   else:
     # it is some 'not'
     assert check.getMagic == mNot
-    result = buildProperFieldCheck(access, check.sons[1]).neg
+    result = buildProperFieldCheck(access, check.sons[1], o).neg(o)
 
-proc checkFieldAccess*(m: TModel, n: PNode) =
+proc checkFieldAccess*(m: TModel, n: PNode; conf: ConfigRef) =
   for i in 1..n.len-1:
-    let check = buildProperFieldCheck(n.sons[0], n.sons[i])
+    let check = buildProperFieldCheck(n.sons[0], n.sons[i], m.o)
     if check != nil and m.doesImply(check) != impYes:
-      message(n.info, warnProveField, renderTree(n.sons[0])); break
+      message(conf, n.info, warnProveField, renderTree(n.sons[0])); break
diff --git a/compiler/hlo.nim b/compiler/hlo.nim
index c4288c362..8251e3179 100644
--- a/compiler/hlo.nim
+++ b/compiler/hlo.nim
@@ -12,12 +12,12 @@
 proc hlo(c: PContext, n: PNode): PNode
 
 proc evalPattern(c: PContext, n, orig: PNode): PNode =
-  internalAssert n.kind == nkCall and n.sons[0].kind == nkSym
+  internalAssert c.config, n.kind == nkCall and n.sons[0].kind == nkSym
   # we need to ensure that the resulting AST is semchecked. However, it's
   # aweful to semcheck before macro invocation, so we don't and treat
   # templates and macros as immediate in this context.
   var rule: string
-  if optHints in gOptions and hintPattern in gNotes:
+  if optHints in c.config.options and hintPattern in c.config.notes:
     rule = renderTree(n, {renderNoComments})
   let s = n.sons[0].sym
   case s.kind
@@ -27,8 +27,8 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode =
     result = semTemplateExpr(c, n, s, {efFromHlo})
   else:
     result = semDirectOp(c, n, {})
-  if optHints in gOptions and hintPattern in gNotes:
-    message(orig.info, hintPattern, rule & " --> '" &
+  if optHints in c.config.options and hintPattern in c.config.notes:
+    message(c.config, orig.info, hintPattern, rule & " --> '" &
       renderTree(result, {renderNoComments}) & "'")
 
 proc applyPatterns(c: PContext, n: PNode): PNode =
@@ -45,7 +45,7 @@ proc applyPatterns(c: PContext, n: PNode): PNode =
         # better be safe than sorry, so check evalTemplateCounter too:
         inc(evalTemplateCounter)
         if evalTemplateCounter > evalTemplateLimit:
-          globalError(n.info, errTemplateInstantiationTooNested)
+          globalError(c.config, n.info, "template instantiation too nested")
         # deactivate this pattern:
         c.patterns[i] = nil
         if x.kind == nkStmtList:
@@ -86,18 +86,18 @@ proc hlo(c: PContext, n: PNode): PNode =
       else:
         result = fitNode(c, n.typ, result, n.info)
       # optimization has been applied so check again:
-      result = commonOptimizations(c.module, result)
+      result = commonOptimizations(c.graph, c.module, result)
       result = hlo(c, result)
-      result = commonOptimizations(c.module, result)
+      result = commonOptimizations(c.graph, c.module, result)
 
 proc hloBody(c: PContext, n: PNode): PNode =
   # fast exit:
-  if c.patterns.len == 0 or optPatterns notin gOptions: return n
+  if c.patterns.len == 0 or optPatterns notin c.config.options: return n
   c.hloLoopDetector = 0
   result = hlo(c, n)
 
 proc hloStmt(c: PContext, n: PNode): PNode =
   # fast exit:
-  if c.patterns.len == 0 or optPatterns notin gOptions: return n
+  if c.patterns.len == 0 or optPatterns notin c.config.options: return n
   c.hloLoopDetector = 0
   result = hlo(c, n)
diff --git a/compiler/idgen.nim b/compiler/idgen.nim
index c6b1a4d07..7d103ffd7 100644
--- a/compiler/idgen.nim
+++ b/compiler/idgen.nim
@@ -36,20 +36,20 @@ proc setId*(id: int) {.inline.} =
 proc idSynchronizationPoint*(idRange: int) =
   gFrontEndId = (gFrontEndId div idRange + 1) * idRange + 1
 
-proc toGid(f: string): string =
+proc toGid(conf: ConfigRef; f: string): string =
   # we used to use ``f.addFileExt("gid")`` (aka ``$project.gid``), but this
   # will cause strange bugs if multiple projects are in the same folder, so
   # we simply use a project independent name:
-  result = options.completeGeneratedFilePath("nim.gid")
+  result = options.completeGeneratedFilePath(conf, "nim.gid")
 
-proc saveMaxIds*(project: string) =
-  var f = open(project.toGid, fmWrite)
+proc saveMaxIds*(conf: ConfigRef; project: string) =
+  var f = open(toGid(conf, project), fmWrite)
   f.writeLine($gFrontEndId)
   f.close()
 
-proc loadMaxIds*(project: string) =
+proc loadMaxIds*(conf: ConfigRef; project: string) =
   var f: File
-  if open(f, project.toGid, fmRead):
+  if open(f, toGid(conf, project), fmRead):
     var line = newStringOfCap(20)
     if f.readLine(line):
       var frontEndId = parseInt(line)
diff --git a/compiler/importer.nim b/compiler/importer.nim
index a5c361864..90e774a50 100644
--- a/compiler/importer.nim
+++ b/compiler/importer.nim
@@ -11,16 +11,16 @@
 
 import
   intsets, strutils, os, ast, astalgo, msgs, options, idents, rodread, lookups,
-  semdata, passes, renderer, modulepaths, sigmatch
+  semdata, passes, renderer, modulepaths, sigmatch, configuration
 
 proc evalImport*(c: PContext, n: PNode): PNode
 proc evalFrom*(c: PContext, n: PNode): PNode
 
-proc readExceptSet*(n: PNode): IntSet =
+proc readExceptSet*(c: PContext, n: PNode): IntSet =
   assert n.kind in {nkImportExceptStmt, nkExportExceptStmt}
   result = initIntSet()
   for i in 1 ..< n.len:
-    let ident = lookups.considerQuotedIdent(n[i])
+    let ident = lookups.considerQuotedIdent(c.config, n[i])
     result.incl(ident.id)
 
 proc importPureEnumField*(c: PContext; s: PSym) =
@@ -47,7 +47,7 @@ proc rawImportSymbol(c: PContext, s: PSym) =
       for j in countup(0, sonsLen(etyp.n) - 1):
         var e = etyp.n.sons[j].sym
         if e.kind != skEnumField:
-          internalError(s.info, "rawImportSymbol")
+          internalError(c.config, s.info, "rawImportSymbol")
           # BUGFIX: because of aliases for enums the symbol may already
           # have been put into the symbol table
           # BUGFIX: but only iff they are the same symbols!
@@ -69,14 +69,14 @@ proc rawImportSymbol(c: PContext, s: PSym) =
     if hasPattern(s): addPattern(c, s)
 
 proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
-  let ident = lookups.considerQuotedIdent(n)
+  let ident = lookups.considerQuotedIdent(c.config, n)
   let s = strTableGet(fromMod.tab, ident)
   if s == nil:
     errorUndeclaredIdentifier(c, n.info, ident.s)
   else:
     if s.kind == skStub: loadStub(s)
     if s.kind notin ExportableSymKinds:
-      internalError(n.info, "importSymbol: 2")
+      internalError(c.config, n.info, "importSymbol: 2")
     # for an enumeration we have to add all identifiers
     case s.kind
     of skProcKinds:
@@ -84,7 +84,7 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
       var it: TIdentIter
       var e = initIdentIter(it, fromMod.tab, s.name)
       while e != nil:
-        if e.name.id != s.name.id: internalError(n.info, "importSymbol: 3")
+        if e.name.id != s.name.id: internalError(c.config, n.info, "importSymbol: 3")
         rawImportSymbol(c, e)
         e = nextIdentIter(it, fromMod.tab)
     else: rawImportSymbol(c, s)
@@ -96,7 +96,7 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
     if s.kind != skModule:
       if s.kind != skEnumField:
         if s.kind notin ExportableSymKinds:
-          internalError(s.info, "importAllSymbols: " & $s.kind)
+          internalError(c.config, s.info, "importAllSymbols: " & $s.kind)
         if exceptSet.isNil or s.name.id notin exceptSet:
           rawImportSymbol(c, s)
     s = nextIter(i, fromMod.tab)
@@ -117,22 +117,23 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet) =
       elif exceptSet.isNil or s.name.id notin exceptSet:
         rawImportSymbol(c, s)
   of nkExportExceptStmt:
-    localError(n.info, errGenerated, "'export except' not implemented")
+    localError(c.config, n.info, "'export except' not implemented")
   else:
     for i in 0..safeLen(n)-1:
       importForwarded(c, n.sons[i], exceptSet)
 
-proc importModuleAs(n: PNode, realModule: PSym): PSym =
+proc importModuleAs(c: PContext; n: PNode, realModule: PSym): PSym =
   result = realModule
   if n.kind != nkImportAs: discard
   elif n.len != 2 or n.sons[1].kind != nkIdent:
-    localError(n.info, errGenerated, "module alias must be an identifier")
+    localError(c.config, n.info, "module alias must be an identifier")
   elif n.sons[1].ident.id != realModule.name.id:
     # some misguided guy will write 'import abc.foo as foo' ...
-    result = createModuleAlias(realModule, n.sons[1].ident, realModule.info)
+    result = createModuleAlias(realModule, n.sons[1].ident, realModule.info,
+                               c.config.options)
 
 proc myImportModule(c: PContext, n: PNode): PSym =
-  var f = checkModuleName(n)
+  var f = checkModuleName(c.config, n)
   if f != InvalidFileIDX:
     let L = c.graph.importStack.len
     let recursion = c.graph.importStack.find(f)
@@ -145,7 +146,7 @@ proc myImportModule(c: PContext, n: PNode): PSym =
         err.add toFullPath(c.graph.importStack[i]) & " imports " &
                 toFullPath(c.graph.importStack[i+1])
       c.recursiveDep = err
-    result = importModuleAs(n, gImportModule(c.graph, c.module, f, c.cache))
+    result = importModuleAs(c, n, gImportModule(c.graph, c.module, f, c.cache))
     #echo "set back to ", L
     c.graph.importStack.setLen(L)
     # we cannot perform this check reliably because of
@@ -153,13 +154,13 @@ proc myImportModule(c: PContext, n: PNode): PSym =
     when true:
       if result.info.fileIndex == c.module.info.fileIndex and
           result.info.fileIndex == n.info.fileIndex:
-        localError(n.info, errGenerated, "A module cannot import itself")
+        localError(c.config, n.info, "A module cannot import itself")
     if sfDeprecated in result.flags:
       if result.constraint != nil:
-        message(n.info, warnDeprecated, result.constraint.strVal & "; " & result.name.s)
+        message(c.config, n.info, warnDeprecated, result.constraint.strVal & "; " & result.name.s)
       else:
-        message(n.info, warnDeprecated, result.name.s)
-    suggestSym(n.info, result, c.graph.usageSym, false)
+        message(c.config, n.info, warnDeprecated, result.name.s)
+    suggestSym(c.config, n.info, result, c.graph.usageSym, false)
 
 proc impMod(c: PContext; it: PNode) =
   let m = myImportModule(c, it)
@@ -189,7 +190,7 @@ proc evalImport(c: PContext, n: PNode): PNode =
 
 proc evalFrom(c: PContext, n: PNode): PNode =
   result = n
-  checkMinSonsLen(n, 2)
+  checkMinSonsLen(n, 2, c.config)
   var m = myImportModule(c, n.sons[0])
   if m != nil:
     n.sons[0] = newSymNode(m)
@@ -200,10 +201,10 @@ proc evalFrom(c: PContext, n: PNode): PNode =
 
 proc evalImportExcept*(c: PContext, n: PNode): PNode =
   result = n
-  checkMinSonsLen(n, 2)
+  checkMinSonsLen(n, 2, c.config)
   var m = myImportModule(c, n.sons[0])
   if m != nil:
     n.sons[0] = newSymNode(m)
     addDecl(c, m, n.info)               # add symbol to symbol table of module
-    importAllSymbolsExcept(c, m, readExceptSet(n))
+    importAllSymbolsExcept(c, m, readExceptSet(c, n))
     #importForwarded(c, m.ast, exceptSet)
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 2ae3426ab..25b554f7b 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -32,13 +32,15 @@ import
   ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options,
   nversion, nimsets, msgs, std / sha1, bitsets, idents, types, os, tables,
   times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils,
-  intsets, cgmeth, lowerings, sighashes
+  intsets, cgmeth, lowerings, sighashes, configuration
 
 from modulegraphs import ModuleGraph
 
 type
   TJSGen = object of TPassContext
     module: PSym
+    graph: ModuleGraph
+    config: ConfigRef
     sigConflicts: CountTable[SigHash]
 
   BModule = ref TJSGen
@@ -94,14 +96,14 @@ type
     up: PProc     # up the call chain; required for closure support
     declaredGlobals: IntSet
 
-var indent = "\t".rope
+template config*(p: PProc): ConfigRef = p.module.config
 
 proc indentLine(p: PProc, r: Rope): Rope =
   result = r
   var p = p
   while true:
     for i in countup(0, p.blocks.len - 1 + p.extraIndent):
-      prepend(result, indent)
+      prepend(result, "\t".rope)
     if p.up == nil or p.up.prc != p.prc.owner:
       break
     p = p.up
@@ -194,7 +196,7 @@ proc mapType(typ: PType): TJSTypeKind =
     else: result = etyNone
   of tyProc: result = etyProc
   of tyCString: result = etyString
-  of tyUnused, tyOptAsRef: internalError("mapType")
+  of tyUnused, tyOptAsRef: doAssert(false, "mapType")
 
 proc mapType(p: PProc; typ: PType): TJSTypeKind =
   result = mapType(typ)
@@ -243,7 +245,7 @@ proc mangleName(m: BModule, s: PSym): Rope =
         inc i
       result = rope(x)
     if s.name.s != "this" and s.kind != skField:
-      if optHotCodeReloading in gOptions:
+      if optHotCodeReloading in m.config.options:
         # When hot reloading is enabled, we must ensure that the names
         # of functions and types will be preserved across rebuilds:
         add(result, idOrSig(s, m.module.name.s, m.sigConflicts))
@@ -286,18 +288,17 @@ proc genConstant(p: PProc, c: PSym)
 
 proc useMagic(p: PProc, name: string) =
   if name.len == 0: return
-  var s = magicsys.getCompilerProc(name)
+  var s = magicsys.getCompilerProc(p.module.graph, name)
   if s != nil:
-    internalAssert s.kind in {skProc, skFunc, skMethod, skConverter}
+    internalAssert p.config, s.kind in {skProc, skFunc, skMethod, skConverter}
     if not p.g.generatedSyms.containsOrIncl(s.id):
       let code = genProc(p, s)
       add(p.g.constants, code)
   else:
-    # we used to exclude the system module from this check, but for DLL
-    # generation support this sloppyness leads to hard to detect bugs, so
-    # we're picky here for the system module too:
-    if p.prc != nil: globalError(p.prc.info, errSystemNeeds, name)
-    else: rawMessage(errSystemNeeds, name)
+    if p.prc != nil:
+      globalError(p.config, p.prc.info, "system module needs: " & name)
+    else:
+      rawMessage(p.config, errGenerated, "system module needs: " & name)
 
 proc isSimpleExpr(p: PProc; n: PNode): bool =
   # calls all the way down --> can stay expression based
@@ -547,7 +548,7 @@ proc genLineDir(p: PProc, n: PNode) =
 proc genWhileStmt(p: PProc, n: PNode) =
   var
     cond: TCompRes
-  internalAssert isEmptyType(n.typ)
+  internalAssert p.config, isEmptyType(n.typ)
   genLineDir(p, n)
   inc(p.unique)
   var length = len(p.blocks)
@@ -634,7 +635,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
       useMagic(p, "isObj")
       for j in countup(0, blen - 2):
         if n.sons[i].sons[j].kind != nkType:
-          internalError(n.info, "genTryStmt")
+          internalError(p.config, n.info, "genTryStmt")
         if orExpr != nil: add(orExpr, "||")
         addf(orExpr, "isObj($2lastJSError.m_type, $1)",
              [genTypeInfo(p, n.sons[i].sons[j].typ), dollar])
@@ -648,7 +649,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
     if not generalCatchBranchExists:
       useMagic(p, "reraiseException")
       line(p, "else {" & tnl)
-      line(p, indent & "reraiseException();" & tnl)
+      line(p, "\treraiseException();" & tnl)
       line(p, "}" & tnl)
     addf(p.body, "$1lastJSError = $1prevJSError;$n", [dollar])
   line(p, "} finally {" & tnl)
@@ -701,7 +702,7 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
             case e.kind
             of nkStrLit..nkTripleStrLit: lineF(p, "case $1:$n",
                 [makeJSString(e.strVal, false)])
-            else: internalError(e.info, "jsgen.genCaseStmt: 2")
+            else: internalError(p.config, e.info, "jsgen.genCaseStmt: 2")
           else:
             gen(p, e, cond)
             lineF(p, "case $1:$n", [cond.rdLoc])
@@ -715,7 +716,7 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
         gen(p, it.sons[0], stmt)
         moveInto(p, stmt, r)
         lineF(p, "break;$n", [])
-    else: internalError(it.info, "jsgen.genCaseStmt")
+    else: internalError(p.config, it.info, "jsgen.genCaseStmt")
   lineF(p, "}$n", [])
 
 proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
@@ -723,7 +724,7 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
   let idx = len(p.blocks)
   if n.sons[0].kind != nkEmpty:
     # named block?
-    if (n.sons[0].kind != nkSym): internalError(n.info, "genBlock")
+    if (n.sons[0].kind != nkSym): internalError(p.config, n.info, "genBlock")
     var sym = n.sons[0].sym
     sym.loc.k = locOther
     sym.position = idx+1
@@ -749,7 +750,7 @@ proc genBreakStmt(p: PProc, n: PNode) =
     idx = len(p.blocks) - 1
     while idx >= 0 and not p.blocks[idx].isLoop: dec idx
     if idx < 0 or not p.blocks[idx].isLoop:
-      internalError(n.info, "no loop to break")
+      internalError(p.config, n.info, "no loop to break")
   p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
   lineF(p, "break L$1;$n", [rope(p.blocks[idx].id)])
 
@@ -874,7 +875,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
       elif b.typ == etyBaseIndex:
         lineF(p, "$# = $#;$n", [a.res, b.rdLoc])
       else:
-        internalError(x.info, "genAsgn")
+        internalError(p.config, x.info, "genAsgn")
     else:
       lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
   else:
@@ -904,18 +905,18 @@ proc genSwap(p: PProc, n: PNode) =
   if mapType(p, skipTypes(n.sons[1].typ, abstractVar)) == etyBaseIndex:
     let tmp2 = p.getTemp(false)
     if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
-      internalError(n.info, "genSwap")
+      internalError(p.config, n.info, "genSwap")
     lineF(p, "var $1 = $2; $2 = $3; $3 = $1;$n",
              [tmp, a.address, b.address])
     tmp = tmp2
   lineF(p, "var $1 = $2; $2 = $3; $3 = $1;",
            [tmp, a.res, b.res])
 
-proc getFieldPosition(f: PNode): int =
+proc getFieldPosition(p: PProc; f: PNode): int =
   case f.kind
   of nkIntLit..nkUInt64Lit: result = int(f.intVal)
   of nkSym: result = f.sym.position
-  else: internalError(f.info, "genFieldPosition")
+  else: internalError(p.config, f.info, "genFieldPosition")
 
 proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
@@ -923,13 +924,13 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
   let b = if n.kind == nkHiddenAddr: n.sons[0] else: n
   gen(p, b.sons[0], a)
   if skipTypes(b.sons[0].typ, abstractVarRange).kind == tyTuple:
-    r.res = makeJSString("Field" & $getFieldPosition(b.sons[1]))
+    r.res = makeJSString("Field" & $getFieldPosition(p, b.sons[1]))
   else:
-    if b.sons[1].kind != nkSym: internalError(b.sons[1].info, "genFieldAddr")
+    if b.sons[1].kind != nkSym: internalError(p.config, b.sons[1].info, "genFieldAddr")
     var f = b.sons[1].sym
     if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
     r.res = makeJSString($f.loc.r)
-  internalAssert a.typ != etyBaseIndex
+  internalAssert p.config, a.typ != etyBaseIndex
   r.address = a.res
   r.kind = resExpr
 
@@ -939,9 +940,9 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
   let otyp = skipTypes(n.sons[0].typ, abstractVarRange)
   if otyp.kind == tyTuple:
     r.res = ("$1.Field$2") %
-        [r.res, getFieldPosition(n.sons[1]).rope]
+        [r.res, getFieldPosition(p, n.sons[1]).rope]
   else:
-    if n.sons[1].kind != nkSym: internalError(n.sons[1].info, "genFieldAccess")
+    if n.sons[1].kind != nkSym: internalError(p.config, n.sons[1].info, "genFieldAccess")
     var f = n.sons[1].sym
     if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
     r.res = "$1.$2" % [r.res, f.loc.r]
@@ -951,7 +952,7 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes)
 
 proc genCheckedFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
   let m = if n.kind == nkHiddenAddr: n.sons[0] else: n
-  internalAssert m.kind == nkCheckedFieldExpr
+  internalAssert p.config, m.kind == nkCheckedFieldExpr
   genAddr(p, m, r) # XXX
 
 proc genCheckedFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
@@ -965,7 +966,7 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
   let m = if n.kind == nkHiddenAddr: n.sons[0] else: n
   gen(p, m.sons[0], a)
   gen(p, m.sons[1], b)
-  internalAssert a.typ != etyBaseIndex and b.typ != etyBaseIndex
+  internalAssert p.config, a.typ != etyBaseIndex and b.typ != etyBaseIndex
   r.address = a.res
   var typ = skipTypes(m.sons[0].typ, abstractPtrs)
   if typ.kind == tyArray: first = firstOrd(typ.sons[0])
@@ -987,9 +988,9 @@ proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) =
     genArrayAddr(p, n, r)
   of tyTuple:
     genFieldAddr(p, n, r)
-  else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
+  else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
   r.typ = etyNone
-  if r.res == nil: internalError(n.info, "genArrayAccess")
+  if r.res == nil: internalError(p.config, n.info, "genArrayAccess")
   if ty.kind == tyCString:
     r.res = "$1.charCodeAt($2)" % [r.address, r.res]
   else:
@@ -1009,7 +1010,7 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
   case n.sons[0].kind
   of nkSym:
     let s = n.sons[0].sym
-    if s.loc.r == nil: internalError(n.info, "genAddr: 3")
+    if s.loc.r == nil: internalError(p.config, n.info, "genAddr: 3")
     case s.kind
     of skVar, skLet, skResult:
       r.kind = resExpr
@@ -1031,8 +1032,8 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
       else:
         # 'var openArray' for instance produces an 'addr' but this is harmless:
         gen(p, n.sons[0], r)
-        #internalError(n.info, "genAddr: 4 " & renderTree(n))
-    else: internalError(n.info, "genAddr: 2")
+        #internalError(p.config, n.info, "genAddr: 4 " & renderTree(n))
+    else: internalError(p.config, n.info, "genAddr: 2")
   of nkCheckedFieldExpr:
     genCheckedFieldAddr(p, n, r)
   of nkDotExpr:
@@ -1051,12 +1052,12 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
         genArrayAddr(p, n.sons[0], r)
       of tyTuple:
         genFieldAddr(p, n.sons[0], r)
-      else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
+      else: internalError(p.config, n.sons[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
   of nkObjDownConv:
     gen(p, n.sons[0], r)
   of nkHiddenDeref:
     gen(p, n.sons[0].sons[0], r)
-  else: internalError(n.sons[0].info, "genAddr: " & $n.sons[0].kind)
+  else: internalError(p.config, n.sons[0].info, "genAddr: " & $n.sons[0].kind)
 
 proc thisParam(p: PProc; typ: PType): PType =
   discard
@@ -1090,7 +1091,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
   case s.kind
   of skVar, skLet, skParam, skTemp, skResult, skForVar:
     if s.loc.r == nil:
-      internalError(n.info, "symbol has no generated name: " & s.name.s)
+      internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
     let k = mapType(p, s.typ)
     if k == etyBaseIndex:
       r.typ = etyBaseIndex
@@ -1107,7 +1108,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
   of skConst:
     genConstant(p, s)
     if s.loc.r == nil:
-      internalError(n.info, "symbol has no generated name: " & s.name.s)
+      internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
     r.res = s.loc.r
   of skProc, skFunc, skConverter, skMethod:
     discard mangleName(p.module, s)
@@ -1124,7 +1125,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
       genProcForSymIfNeeded(p, s)
   else:
     if s.loc.r == nil:
-      internalError(n.info, "symbol has no generated name: " & s.name.s)
+      internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
     r.res = s.loc.r
   r.kind = resVal
 
@@ -1145,7 +1146,7 @@ proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
     elif t == etyBaseIndex:
       r.res = "$1[0]" % [a.res]
     else:
-      internalError(n.info, "genDeref")
+      internalError(p.config, n.info, "genDeref")
 
 proc genArgNoParam(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
@@ -1205,14 +1206,14 @@ proc genArgs(p: PProc, n: PNode, r: var TCompRes; start=1) =
     # XXX look into this:
     let jsp = countJsParams(typ)
     if emitted != jsp and tfVarargs notin typ.flags:
-      localError(n.info, "wrong number of parameters emitted; expected: " & $jsp &
+      localError(p.config, n.info, "wrong number of parameters emitted; expected: " & $jsp &
         " but got: " & $emitted)
   r.kind = resExpr
 
 proc genOtherArg(p: PProc; n: PNode; i: int; typ: PType;
                  generated: var int; r: var TCompRes) =
   if i >= n.len:
-    globalError(n.info, "wrong importcpp pattern; expected parameter at position " & $i &
+    globalError(p.config, n.info, "wrong importcpp pattern; expected parameter at position " & $i &
         " but got only: " & $(n.len-1))
   let it = n[i]
   var paramType: PNode = nil
@@ -1266,7 +1267,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
   if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
   if sfInfixCall in f.flags:
     let pat = n.sons[0].sym.loc.r.data
-    internalAssert pat != nil
+    internalAssert p.config, pat != nil
     if pat.contains({'#', '(', '@'}):
       var typ = skipTypes(n.sons[0].typ, abstractInst)
       assert(typ.kind == tyProc)
@@ -1276,7 +1277,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
     gen(p, n.sons[1], r)
     if r.typ == etyBaseIndex:
       if r.address == nil:
-        globalError(n.info, "cannot invoke with infix syntax")
+        globalError(p.config, n.info, "cannot invoke with infix syntax")
       r.res = "$1[$2]" % [r.address, r.res]
       r.address = nil
       r.typ = etyNone
@@ -1295,7 +1296,7 @@ proc genCall(p: PProc, n: PNode, r: var TCompRes) =
 
 proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
   let n = n[1].skipConv
-  internalAssert n.kind == nkBracket
+  internalAssert p.config, n.kind == nkBracket
   useMagic(p, "toJSStr") # Used in rawEcho
   useMagic(p, "rawEcho")
   add(r.res, "rawEcho(")
@@ -1326,7 +1327,7 @@ proc createRecordVarAux(p: PProc, rec: PNode, excludedFieldIDs: IntSet, output:
       if output.len > 0: output.add(", ")
       output.addf("$#: ", [mangleName(p.module, rec.sym)])
       output.add(createVar(p, rec.sym.typ, false))
-  else: internalError(rec.info, "createRecordVarAux")
+  else: internalError(p.config, rec.info, "createRecordVarAux")
 
 proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: var Rope) =
   var t = typ
@@ -1409,10 +1410,10 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
     if t.n != nil:
       result = createVar(p, lastSon t, indirect)
     else:
-      internalError("createVar: " & $t.kind)
+      internalError(p.config, "createVar: " & $t.kind)
       result = nil
   else:
-    internalError("createVar: " & $t.kind)
+    internalError(p.config, "createVar: " & $t.kind)
     result = nil
 
 template returnType: untyped =
@@ -1424,7 +1425,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
     s: Rope
     varCode: string
     varName = mangleName(p.module, v)
-    useReloadingGuard = sfGlobal in v.flags and optHotCodeReloading in gOptions
+    useReloadingGuard = sfGlobal in v.flags and optHotCodeReloading in p.config.options
 
   if v.constraint.isNil:
     if useReloadingGuard:
@@ -1482,7 +1483,7 @@ proc genVarStmt(p: PProc, n: PNode) =
     var a = n.sons[i]
     if a.kind != nkCommentStmt:
       if a.kind == nkVarTuple:
-        let unpacked = lowerTupleUnpacking(a, p.prc)
+        let unpacked = lowerTupleUnpacking(p.module.graph, a, p.prc)
         genStmt(p, unpacked)
       else:
         assert(a.kind == nkIdentDefs)
@@ -1519,7 +1520,7 @@ proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
   case skipTypes(n.sons[1].typ, abstractVar).kind
   of tyEnum, tyInt..tyUInt64, tyChar: gen(p, n.sons[1], r)
   of tyBool: unaryExpr(p, n, r, "", "($1 ? 1:0)")
-  else: internalError(n.info, "genOrd")
+  else: internalError(p.config, n.info, "genOrd")
 
 proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
@@ -1559,9 +1560,9 @@ proc genToArray(p: PProc; n: PNode; r: var TCompRes) =
         gen(p, it[1], b)
         r.res.add("$# => $#" % [a.rdLoc, b.rdLoc])
       else:
-        localError(it.info, "'toArray' needs tuple constructors")
+        localError(p.config, it.info, "'toArray' needs tuple constructors")
   else:
-    localError(x.info, "'toArray' needs an array literal")
+    localError(p.config, x.info, "'toArray' needs an array literal")
   r.res.add(")")
 
 proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = nil) =
@@ -1604,7 +1605,7 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
   of tySet:
     genReprAux(p, n, r, "reprSet", genTypeInfo(p, t))
   of tyEmpty, tyVoid:
-    localError(n.info, "'repr' doesn't support 'void' type")
+    localError(p.config, n.info, "'repr' doesn't support 'void' type")
   of tyPointer:
     genReprAux(p, n, r, "reprPointer")
   of tyOpenArray, tyVarargs:
@@ -1736,7 +1737,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
   of mReset: genReset(p, n)
   of mEcho: genEcho(p, n, r)
   of mNLen..mNError, mSlurp, mStaticExec:
-    localError(n.info, errXMustBeCompileTime, n.sons[0].sym.name.s)
+    localError(p.config, n.info, errXMustBeCompileTime % n.sons[0].sym.name.s)
   of mCopyStr:
     binaryExpr(p, n, r, "", "($1.slice($2))")
   of mCopyStrLast:
@@ -1754,7 +1755,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
     genCall(p, n, r)
   else:
     genCall(p, n, r)
-    #else internalError(e.info, 'genMagic: ' + magicToStr[op]);
+    #else internalError(p.config, e.info, 'genMagic: ' + magicToStr[op]);
 
 proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) =
   var
@@ -1810,7 +1811,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
   for i in countup(1, sonsLen(n) - 1):
     if i > 1: add(initList, ", ")
     var it = n.sons[i]
-    internalAssert it.kind == nkExprColonExpr
+    internalAssert p.config, it.kind == nkExprColonExpr
     let val = it.sons[1]
     gen(p, val, a)
     var f = it.sons[0].sym
@@ -1866,7 +1867,7 @@ proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) =
     gen(p, n.sons[0].sons[0], r)
   else:
     gen(p, n.sons[0], r)
-    if r.res == nil: internalError(n.info, "convStrToCStr")
+    if r.res == nil: internalError(p.config, n.info, "convStrToCStr")
     useMagic(p, "toJSStr")
     r.res = "toJSStr($1)" % [r.res]
     r.kind = resExpr
@@ -1878,13 +1879,13 @@ proc convCStrToStr(p: PProc, n: PNode, r: var TCompRes) =
     gen(p, n.sons[0].sons[0], r)
   else:
     gen(p, n.sons[0], r)
-    if r.res == nil: internalError(n.info, "convCStrToStr")
+    if r.res == nil: internalError(p.config, n.info, "convCStrToStr")
     useMagic(p, "cstrToNimstr")
     r.res = "cstrToNimstr($1)" % [r.res]
     r.kind = resExpr
 
 proc genReturnStmt(p: PProc, n: PNode) =
-  if p.procDef == nil: internalError(n.info, "genReturnStmt")
+  if p.procDef == nil: internalError(p.config, n.info, "genReturnStmt")
   p.beforeRetNeeded = true
   if n.sons[0].kind != nkEmpty:
     genStmt(p, n.sons[0])
@@ -1969,7 +1970,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
   else:
     result = ~tnl
 
-    if optHotCodeReloading in gOptions:
+    if optHotCodeReloading in p.config.options:
       # Here, we introduce thunks that create the equivalent of a jump table
       # for all global functions, because references to them may be stored
       # in JavaScript variables. The added indirection ensures that such
@@ -2140,7 +2141,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
   of nkVarSection, nkLetSection: genVarStmt(p, n)
   of nkConstSection: discard
   of nkForStmt, nkParForStmt:
-    internalError(n.info, "for statement not eliminated")
+    internalError(p.config, n.info, "for statement not eliminated")
   of nkCaseStmt: genCaseJS(p, n, r)
   of nkReturnStmt: genReturnStmt(p, n)
   of nkBreakStmt: genBreakStmt(p, n)
@@ -2163,13 +2164,13 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
       genSym(p, n.sons[namePos], r)
       r.res = nil
   of nkGotoState, nkState:
-    internalError(n.info, "first class iterators not implemented")
+    internalError(p.config, n.info, "first class iterators not implemented")
   of nkPragmaBlock: gen(p, n.lastSon, r)
   of nkComesFrom:
     discard "XXX to implement for better stack traces"
-  else: internalError(n.info, "gen: unknown node type: " & $n.kind)
+  else: internalError(p.config, n.info, "gen: unknown node type: " & $n.kind)
 
-var globals: PGlobals
+var globals: PGlobals # XXX global variable here
 
 proc newModule(module: PSym): BModule =
   new(result)
@@ -2205,10 +2206,10 @@ proc genModule(p: PProc, n: PNode) =
     add(p.body, frameDestroy(p))
 
 proc myProcess(b: PPassContext, n: PNode): PNode =
-  if passes.skipCodegen(n): return n
   result = n
-  var m = BModule(b)
-  if m.module == nil: internalError(n.info, "myProcess")
+  let m = BModule(b)
+  if passes.skipCodegen(m.config, n): return n
+  if m.module == nil: internalError(m.config, n.info, "myProcess")
   var p = newProc(globals, m, nil, m.module.options)
   p.unique = globals.unique
   genModule(p, n)
@@ -2235,11 +2236,11 @@ proc getClassName(t: PType): Rope =
   if s.isNil or sfAnon in s.flags:
     s = skipTypes(t, abstractPtrs).sym
   if s.isNil or sfAnon in s.flags:
-    internalError("cannot retrieve class name")
+    doAssert(false, "cannot retrieve class name")
   if s.loc.r != nil: result = s.loc.r
   else: result = rope(s.name.s)
 
-proc genClass(obj: PType; content: Rope; ext: string) =
+proc genClass(conf: ConfigRef; obj: PType; content: Rope; ext: string) =
   let cls = getClassName(obj)
   let t = skipTypes(obj, abstractPtrs)
   let extends = if t.kind == tyObject and t.sons[0] != nil:
@@ -2252,34 +2253,36 @@ proc genClass(obj: PType; content: Rope; ext: string) =
             "class $#$# {$n$#$n}$n") %
            [rope(VersionAsString), cls, extends, content]
 
-  let outfile = changeFileExt(completeCFilePath($cls), ext)
+  let outfile = changeFileExt(completeCFilePath(conf, $cls), ext)
   discard writeRopeIfNotEqual(result, outfile)
 
 proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
-  if passes.skipCodegen(n): return n
   result = myProcess(b, n)
   var m = BModule(b)
+  if passes.skipCodegen(m.config, n): return n
   if sfMainModule in m.module.flags:
     let ext = "js"
     let f = if globals.classes.len == 0: toFilename(FileIndex m.module.position)
             else: "nimsystem"
     let code = wholeCode(graph, m)
     let outfile =
-      if options.outFile.len > 0:
-        if options.outFile.isAbsolute: options.outFile
-        else: getCurrentDir() / options.outFile
+      if m.config.outFile.len > 0:
+        if m.config.outFile.isAbsolute: m.config.outFile
+        else: getCurrentDir() / m.config.outFile
       else:
-        changeFileExt(completeCFilePath(f), ext)
+        changeFileExt(completeCFilePath(m.config, f), ext)
     discard writeRopeIfNotEqual(genHeader() & code, outfile)
     for obj, content in items(globals.classes):
-      genClass(obj, content, ext)
+      genClass(m.config, obj, content, ext)
 
 proc myOpenCached(graph: ModuleGraph; s: PSym, rd: PRodReader): PPassContext =
-  internalError("symbol files are not possible with the JS code generator")
+  internalError(graph.config, "symbol files are not possible with the JS code generator")
   result = nil
 
 proc myOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext =
   var r = newModule(s)
+  r.graph = graph
+  r.config = graph.config
   result = r
 
 const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim
index f440ee7da..f9e4246eb 100644
--- a/compiler/jstypes.nim
+++ b/compiler/jstypes.nim
@@ -38,7 +38,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
                     makeJSString(field.name.s)]
   of nkRecCase:
     length = sonsLen(n)
-    if (n.sons[0].kind != nkSym): internalError(n.info, "genObjectFields")
+    if (n.sons[0].kind != nkSym): internalError(p.config, n.info, "genObjectFields")
     field = n.sons[0].sym
     s = genTypeInfo(p, field.typ)
     for i in countup(1, length - 1):
@@ -47,7 +47,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
       case b.kind
       of nkOfBranch:
         if sonsLen(b) < 2:
-          internalError(b.info, "genObjectFields; nkOfBranch broken")
+          internalError(p.config, b.info, "genObjectFields; nkOfBranch broken")
         for j in countup(0, sonsLen(b) - 2):
           if u != nil: add(u, ", ")
           if b.sons[j].kind == nkRange:
@@ -57,7 +57,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
             add(u, rope(getOrdValue(b.sons[j])))
       of nkElse:
         u = rope(lengthOrd(field.typ))
-      else: internalError(n.info, "genObjectFields(nkRecCase)")
+      else: internalError(p.config, n.info, "genObjectFields(nkRecCase)")
       if result != nil: add(result, ", " & tnl)
       addf(result, "[setConstr($1), $2]",
            [u, genObjectFields(p, typ, lastSon(b))])
@@ -65,7 +65,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
         "typ: $2, name: $4, sons: [$5]}") % [
         mangleName(p.module, field), s,
         rope(lengthOrd(field.typ)), makeJSString(field.name.s), result]
-  else: internalError(n.info, "genObjectFields")
+  else: internalError(p.config, n.info, "genObjectFields")
 
 proc objHasTypeField(t: PType): bool {.inline.} =
   tfInheritable in t.flags or t.sons[0] != nil
@@ -104,7 +104,7 @@ proc genEnumInfo(p: PProc, typ: PType, name: Rope) =
   let length = sonsLen(typ.n)
   var s: Rope = nil
   for i in countup(0, length - 1):
-    if (typ.n.sons[i].kind != nkSym): internalError(typ.n.info, "genEnumInfo")
+    if (typ.n.sons[i].kind != nkSym): internalError(p.config, typ.n.info, "genEnumInfo")
     let field = typ.n.sons[i].sym
     if i > 0: add(s, ", " & tnl)
     let extName = if field.ast == nil: field.name.s else: field.ast.strVal
@@ -152,5 +152,5 @@ proc genTypeInfo(p: PProc, typ: PType): Rope =
   of tyTuple: genTupleInfo(p, t, result)
   of tyStatic:
     if t.n != nil: result = genTypeInfo(p, lastSon t)
-    else: internalError("genTypeInfo(" & $t.kind & ')')
-  else: internalError("genTypeInfo(" & $t.kind & ')')
+    else: internalError(p.config, "genTypeInfo(" & $t.kind & ')')
+  else: internalError(p.config, "genTypeInfo(" & $t.kind & ')')
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index 43ff50190..40e5bb6b0 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -11,7 +11,7 @@
 
 import
   intsets, strutils, options, ast, astalgo, trees, treetab, msgs,
-  idents, renderer, types, magicsys, rodread, lowerings, tables
+  idents, renderer, types, magicsys, rodread, lowerings, tables, modulegraphs
 
 discard """
   The basic approach is that captured vars need to be put on the heap and
@@ -125,32 +125,32 @@ proc newCall(a: PSym, b: PNode): PNode =
   result.add newSymNode(a)
   result.add b
 
-proc createClosureIterStateType*(iter: PSym): PType =
+proc createClosureIterStateType*(g: ModuleGraph; iter: PSym): PType =
   var n = newNodeI(nkRange, iter.info)
   addSon(n, newIntNode(nkIntLit, -1))
   addSon(n, newIntNode(nkIntLit, 0))
   result = newType(tyRange, iter)
   result.n = n
-  var intType = nilOrSysInt()
+  var intType = nilOrSysInt(g)
   if intType.isNil: intType = newType(tyInt, iter)
   rawAddSon(result, intType)
 
-proc createStateField(iter: PSym): PSym =
+proc createStateField(g: ModuleGraph; iter: PSym): PSym =
   result = newSym(skField, getIdent(":state"), iter, iter.info)
-  result.typ = createClosureIterStateType(iter)
+  result.typ = createClosureIterStateType(g, iter)
 
-proc createEnvObj(owner: PSym; info: TLineInfo): PType =
+proc createEnvObj(g: ModuleGraph; owner: PSym; info: TLineInfo): PType =
   # YYY meh, just add the state field for every closure for now, it's too
   # hard to figure out if it comes from a closure iterator:
-  result = createObj(owner, info, final=false)
-  rawAddField(result, createStateField(owner))
+  result = createObj(g, owner, info, final=false)
+  rawAddField(result, createStateField(g, owner))
 
 proc getClosureIterResult*(iter: PSym): PSym =
   if resultPos < iter.ast.len:
     result = iter.ast.sons[resultPos].sym
   else:
     # XXX a bit hacky:
-    result = newSym(skResult, getIdent":result", iter, iter.info)
+    result = newSym(skResult, getIdent":result", iter, iter.info, {})
     result.typ = iter.typ.sons[0]
     incl(result.flags, sfUsed)
     iter.ast.add newSymNode(result)
@@ -166,7 +166,7 @@ proc addHiddenParam(routine: PSym, param: PSym) =
   assert sfFromGeneric in param.flags
   #echo "produced environment: ", param.id, " for ", routine.id
 
-proc getHiddenParam(routine: PSym): PSym =
+proc getHiddenParam(g: ModuleGraph; routine: PSym): PSym =
   let params = routine.ast.sons[paramsPos]
   let hidden = lastSon(params)
   if hidden.kind == nkSym and hidden.sym.kind == skParam and hidden.sym.name.s == paramName:
@@ -174,7 +174,7 @@ proc getHiddenParam(routine: PSym): PSym =
     assert sfFromGeneric in result.flags
   else:
     # writeStackTrace()
-    localError(routine.info, "internal error: could not find env param for " & routine.name.s)
+    localError(g.config, routine.info, "internal error: could not find env param for " & routine.name.s)
     result = routine
 
 proc getEnvParam*(routine: PSym): PSym =
@@ -208,14 +208,14 @@ proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
   result.sons[0] = le
   result.sons[1] = ri
 
-proc makeClosure*(prc: PSym; env: PNode; info: TLineInfo): PNode =
+proc makeClosure*(g: ModuleGraph; prc: PSym; env: PNode; info: TLineInfo): PNode =
   result = newNodeIT(nkClosure, info, prc.typ)
   result.add(newSymNode(prc))
   if env == nil:
-    result.add(newNodeIT(nkNilLit, info, getSysType(tyNil)))
+    result.add(newNodeIT(nkNilLit, info, getSysType(g, info, tyNil)))
   else:
     if env.skipConv.kind == nkClosure:
-      localError(info, "internal error: taking closure of closure")
+      localError(g.config, info, "internal error: taking closure of closure")
     result.add(env)
 
 proc interestingIterVar(s: PSym): bool {.inline.} =
@@ -227,23 +227,23 @@ proc interestingIterVar(s: PSym): bool {.inline.} =
 template isIterator*(owner: PSym): bool =
   owner.kind == skIterator and owner.typ.callConv == ccClosure
 
-proc liftingHarmful(owner: PSym): bool {.inline.} =
+proc liftingHarmful(conf: ConfigRef; owner: PSym): bool {.inline.} =
   ## lambda lifting can be harmful for JS-like code generators.
   let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro
-  result = gCmd == cmdCompileToJS and not isCompileTime
+  result = conf.cmd == cmdCompileToJS and not isCompileTime
 
-proc liftIterSym*(n: PNode; owner: PSym): PNode =
+proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
   # transforms  (iter)  to  (let env = newClosure[iter](); (iter, env))
-  if liftingHarmful(owner): return n
+  if liftingHarmful(g.config, owner): return n
   let iter = n.sym
   assert iter.isIterator
 
   result = newNodeIT(nkStmtListExpr, n.info, n.typ)
 
-  let hp = getHiddenParam(iter)
+  let hp = getHiddenParam(g, iter)
   var env: PNode
   if owner.isIterator:
-    let it = getHiddenParam(owner)
+    let it = getHiddenParam(g, owner)
     addUniqueField(it.typ.sons[0], hp)
     env = indirectAccess(newSymNode(it), hp, hp.info)
   else:
@@ -255,11 +255,11 @@ proc liftIterSym*(n: PNode; owner: PSym): PNode =
     addVar(v, env)
     result.add(v)
   # add 'new' statement:
-  result.add newCall(getSysSym"internalNew", env)
-  result.add makeClosure(iter, env, n.info)
+  result.add newCall(getSysSym(g, n.info, "internalNew"), env)
+  result.add makeClosure(g, iter, env, n.info)
 
-proc freshVarForClosureIter*(s, owner: PSym): PNode =
-  let envParam = getHiddenParam(owner)
+proc freshVarForClosureIter*(g: ModuleGraph; s, owner: PSym): PNode =
+  let envParam = getHiddenParam(g, owner)
   let obj = envParam.typ.lastSon
   addField(obj, s)
 
@@ -269,18 +269,18 @@ proc freshVarForClosureIter*(s, owner: PSym): PNode =
   if field != nil:
     result = rawIndirectAccess(access, field, s.info)
   else:
-    localError(s.info, "internal error: cannot generate fresh variable")
+    localError(g.config, s.info, "internal error: cannot generate fresh variable")
     result = access
 
 # ------------------ new stuff -------------------------------------------
 
-proc markAsClosure(owner: PSym; n: PNode) =
+proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) =
   let s = n.sym
   if illegalCapture(s):
-    localError(n.info, "illegal capture '$1' of type <$2> which is declared here: $3" %
+    localError(g.config, n.info, "illegal capture '$1' of type <$2> which is declared here: $3" %
       [s.name.s, typeToString(s.typ), $s.info])
   elif owner.typ.callConv notin {ccClosure, ccDefault}:
-    localError(n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
+    localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
       [s.name.s, owner.name.s, CallingConvToStr[owner.typ.callConv]])
   incl(owner.typ.flags, tfCapturesEnv)
   owner.typ.callConv = ccClosure
@@ -290,12 +290,14 @@ type
     processed, capturedVars: IntSet
     ownerToType: Table[int, PType]
     somethingToDo: bool
+    graph: ModuleGraph
 
-proc initDetectionPass(fn: PSym): DetectionPass =
+proc initDetectionPass(g: ModuleGraph; fn: PSym): DetectionPass =
   result.processed = initIntSet()
   result.capturedVars = initIntSet()
   result.ownerToType = initTable[int, PType]()
   result.processed.incl(fn.id)
+  result.graph = g
 
 discard """
 proc outer =
@@ -312,7 +314,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym;
   result = c.ownerToType.getOrDefault(owner.id)
   if result.isNil:
     result = newType(tyRef, owner)
-    let obj = createEnvObj(owner, info)
+    let obj = createEnvObj(c.graph, owner, info)
     rawAddSon(result, obj)
     c.ownerToType[owner.id] = result
 
@@ -321,13 +323,13 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
   let obj = refObj.lastSon
   let fieldType = c.getEnvTypeForOwner(dep, info) #getHiddenParam(dep).typ
   if refObj == fieldType:
-    localError(dep.info, "internal error: invalid up reference computed")
+    localError(c.graph.config, dep.info, "internal error: invalid up reference computed")
 
   let upIdent = getIdent(upName)
   let upField = lookupInRecord(obj.n, upIdent)
   if upField != nil:
     if upField.typ != fieldType:
-      localError(dep.info, "internal error: up references do not agree")
+      localError(c.graph.config, dep.info, "internal error: up references do not agree")
   else:
     let result = newSym(skField, upIdent, obj.owner, obj.owner.info)
     result.typ = fieldType
@@ -369,7 +371,7 @@ proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) =
     cp.typ = t
     addHiddenParam(fn, cp)
   elif cp.typ != t and fn.kind != skIterator:
-    localError(fn.info, "internal error: inconsistent environment type")
+    localError(c.graph.config, fn.info, "internal error: inconsistent environment type")
   #echo "adding closure to ", fn.name.s
 
 proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
@@ -395,7 +397,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
         addClosureParam(c, owner, n.info)
         if interestingIterVar(s):
           if not c.capturedVars.containsOrIncl(s.id):
-            let obj = getHiddenParam(owner).typ.lastSon
+            let obj = getHiddenParam(c.graph, owner).typ.lastSon
             #let obj = c.getEnvTypeForOwner(s.owner).lastSon
 
             if s.name == getIdent(":state"):
@@ -419,7 +421,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
       """
       # mark 'owner' as taking a closure:
       c.somethingToDo = true
-      markAsClosure(owner, n)
+      markAsClosure(c.graph, owner, n)
       addClosureParam(c, owner, n.info)
       #echo "capturing ", n.info
       # variable 's' is actually captured:
@@ -444,7 +446,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
           """
           let up = w.skipGenericOwner
           #echo "up for ", w.name.s, " up ", up.name.s
-          markAsClosure(w, n)
+          markAsClosure(c.graph, w, n)
           addClosureParam(c, w, n.info) # , ow
           createUpField(c, w, up, n.info)
           w = up
@@ -465,17 +467,16 @@ type
     processed: IntSet
     envVars: Table[int, PNode]
     inContainer: int
-    features: set[Feature]
 
 proc initLiftingPass(fn: PSym): LiftingPass =
   result.processed = initIntSet()
   result.processed.incl(fn.id)
   result.envVars = initTable[int, PNode]()
 
-proc accessViaEnvParam(n: PNode; owner: PSym): PNode =
+proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
   let s = n.sym
   # Type based expression construction for simplicity:
-  let envParam = getHiddenParam(owner)
+  let envParam = getHiddenParam(g, owner)
   if not envParam.isNil:
     var access = newSymNode(envParam)
     while true:
@@ -487,7 +488,7 @@ proc accessViaEnvParam(n: PNode; owner: PSym): PNode =
       let upField = lookupInRecord(obj.n, getIdent(upName))
       if upField == nil: break
       access = rawIndirectAccess(access, upField, n.info)
-  localError(n.info, "internal error: environment misses: " & s.name.s)
+  localError(g.config, n.info, "internal error: environment misses: " & s.name.s)
   result = n
 
 proc newEnvVar(owner: PSym; typ: PType): PNode =
@@ -506,22 +507,22 @@ proc newEnvVar(owner: PSym; typ: PType): PNode =
 proc setupEnvVar(owner: PSym; d: DetectionPass;
                  c: var LiftingPass): PNode =
   if owner.isIterator:
-    return getHiddenParam(owner).newSymNode
+    return getHiddenParam(d.graph, owner).newSymNode
   result = c.envvars.getOrDefault(owner.id)
   if result.isNil:
     let envVarType = d.ownerToType.getOrDefault(owner.id)
     if envVarType.isNil:
-      localError owner.info, "internal error: could not determine closure type"
+      localError d.graph.config, owner.info, "internal error: could not determine closure type"
     result = newEnvVar(owner, envVarType)
     c.envVars[owner.id] = result
 
-proc getUpViaParam(owner: PSym): PNode =
-  let p = getHiddenParam(owner)
+proc getUpViaParam(g: ModuleGraph; owner: PSym): PNode =
+  let p = getHiddenParam(g, owner)
   result = p.newSymNode
   if owner.isIterator:
     let upField = lookupInRecord(p.typ.lastSon.n, getIdent(upName))
     if upField == nil:
-      localError(owner.info, "could not find up reference for closure iter")
+      localError(g.config, owner.info, "could not find up reference for closure iter")
     else:
       result = rawIndirectAccess(result, upField, p.info)
 
@@ -531,7 +532,7 @@ proc rawClosureCreation(owner: PSym;
 
   var env: PNode
   if owner.isIterator:
-    env = getHiddenParam(owner).newSymNode
+    env = getHiddenParam(d.graph, owner).newSymNode
   else:
     env = setupEnvVar(owner, d, c)
     if env.kind == nkSym:
@@ -539,7 +540,7 @@ proc rawClosureCreation(owner: PSym;
       addVar(v, env)
       result.add(v)
     # add 'new' statement:
-    result.add(newCall(getSysSym"internalNew", env))
+    result.add(newCall(getSysSym(d.graph, env.info, "internalNew"), env))
     # add assignment statements for captured parameters:
     for i in 1..<owner.typ.n.len:
       let local = owner.typ.n[i].sym
@@ -550,7 +551,7 @@ proc rawClosureCreation(owner: PSym;
 
   let upField = lookupInRecord(env.typ.lastSon.n, getIdent(upName))
   if upField != nil:
-    let up = getUpViaParam(owner)
+    let up = getUpViaParam(d.graph, owner)
     if up != nil and upField.typ == up.typ:
       result.add(newAsgnStmt(rawIndirectAccess(env, upField, env.info),
                  up, env.info))
@@ -558,7 +559,7 @@ proc rawClosureCreation(owner: PSym;
     #  result.add(newAsgnStmt(rawIndirectAccess(env, upField, env.info),
     #             oldenv, env.info))
     else:
-      localError(env.info, "internal error: cannot create up reference")
+      localError(d.graph.config, env.info, "internal error: cannot create up reference")
 
 proc closureCreationForIter(iter: PNode;
                             d: DetectionPass; c: var LiftingPass): PNode =
@@ -566,10 +567,10 @@ proc closureCreationForIter(iter: PNode;
   let owner = iter.sym.skipGenericOwner
   var v = newSym(skVar, getIdent(envName), owner, iter.info)
   incl(v.flags, sfShadowed)
-  v.typ = getHiddenParam(iter.sym).typ
+  v.typ = getHiddenParam(d.graph, iter.sym).typ
   var vnode: PNode
   if owner.isIterator:
-    let it = getHiddenParam(owner)
+    let it = getHiddenParam(d.graph, owner)
     addUniqueField(it.typ.sons[0], v)
     vnode = indirectAccess(newSymNode(it), v, v.info)
   else:
@@ -577,7 +578,7 @@ proc closureCreationForIter(iter: PNode;
     var vs = newNodeI(nkVarSection, iter.info)
     addVar(vs, vnode)
     result.add(vs)
-  result.add(newCall(getSysSym"internalNew", vnode))
+  result.add(newCall(getSysSym(d.graph, iter.info, "internalNew"), vnode))
 
   let upField = lookupInRecord(v.typ.lastSon.n, getIdent(upName))
   if upField != nil:
@@ -586,8 +587,8 @@ proc closureCreationForIter(iter: PNode;
       result.add(newAsgnStmt(rawIndirectAccess(vnode, upField, iter.info),
                  u, iter.info))
     else:
-      localError(iter.info, "internal error: cannot create up reference for iter")
-  result.add makeClosure(iter.sym, vnode, iter.info)
+      localError(d.graph.config, iter.info, "internal error: cannot create up reference for iter")
+  result.add makeClosure(d.graph, iter.sym, vnode, iter.info)
 
 proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass;
                      c: var LiftingPass): PNode =
@@ -597,11 +598,11 @@ proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass;
   if field != nil:
     result = rawIndirectAccess(access, field, n.info)
   else:
-    localError(n.info, "internal error: not part of closure object type")
+    localError(d.graph.config, n.info, "internal error: not part of closure object type")
     result = n
 
-proc getStateField*(owner: PSym): PSym =
-  getHiddenParam(owner).typ.sons[0].n.sons[0].sym
+proc getStateField*(g: ModuleGraph; owner: PSym): PSym =
+  getHiddenParam(g, owner).typ.sons[0].n.sons[0].sym
 
 proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
                       c: var LiftingPass): PNode
@@ -609,8 +610,8 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
 proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
                     c: var LiftingPass): PNode =
   if c.inContainer > 0:
-    localError(n.info, "invalid control flow: 'yield' within a constructor")
-  let state = getStateField(owner)
+    localError(d.graph.config, n.info, "invalid control flow: 'yield' within a constructor")
+  let state = getStateField(d.graph, owner)
   assert state != nil
   assert state.typ != nil
   assert state.typ.n != nil
@@ -620,7 +621,8 @@ proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
   var stateAsgnStmt = newNodeI(nkAsgn, n.info)
   stateAsgnStmt.add(rawIndirectAccess(newSymNode(getEnvParam(owner)),
                     state, n.info))
-  stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
+  stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo,
+                    getSysType(d.graph, n.info, tyInt)))
 
   var retStmt = newNodeI(nkReturnStmt, n.info)
   if n.sons[0].kind != nkEmpty:
@@ -633,7 +635,8 @@ proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
     retStmt.add(emptyNode)
 
   var stateLabelStmt = newNodeI(nkState, n.info)
-  stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
+  stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo,
+                     getSysType(d.graph, n.info, tyInt)))
 
   result = newNodeI(nkStmtList, n.info)
   result.add(stateAsgnStmt)
@@ -642,16 +645,16 @@ proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
 
 proc transformReturn(n: PNode; owner: PSym; d: DetectionPass;
                      c: var LiftingPass): PNode =
-  let state = getStateField(owner)
+  let state = getStateField(d.graph, owner)
   result = newNodeI(nkStmtList, n.info)
   var stateAsgnStmt = newNodeI(nkAsgn, n.info)
   stateAsgnStmt.add(rawIndirectAccess(newSymNode(getEnvParam(owner)),
                     state, n.info))
-  stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
+  stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(d.graph, n.info, tyInt)))
   result.add(stateAsgnStmt)
   result.add(n)
 
-proc wrapIterBody(n: PNode; owner: PSym): PNode =
+proc wrapIterBody(g: ModuleGraph; n: PNode; owner: PSym): PNode =
   if not owner.isIterator: return n
   when false:
     # unfortunately control flow is still convoluted and we can end up
@@ -665,7 +668,7 @@ proc wrapIterBody(n: PNode; owner: PSym): PNode =
   let info = n.info
   result = newNodeI(nkStmtList, info)
   var gs = newNodeI(nkGotoState, info)
-  gs.add(rawIndirectAccess(newSymNode(owner.getHiddenParam), getStateField(owner), info))
+  gs.add(rawIndirectAccess(newSymNode(getHiddenParam(g, owner)), getStateField(g, owner), info))
   result.add(gs)
   var state0 = newNodeI(nkState, info)
   state0.add(newIntNode(nkIntLit, 0))
@@ -674,9 +677,9 @@ proc wrapIterBody(n: PNode; owner: PSym): PNode =
   result.add(n)
 
   var stateAsgnStmt = newNodeI(nkAsgn, info)
-  stateAsgnStmt.add(rawIndirectAccess(newSymNode(owner.getHiddenParam),
-                    getStateField(owner), info))
-  stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
+  stateAsgnStmt.add(rawIndirectAccess(newSymNode(getHiddenParam(g, owner)),
+                    getStateField(g, owner), info))
+  stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(g, info, tyInt)))
   result.add(stateAsgnStmt)
 
 proc symToClosure(n: PNode; owner: PSym; d: DetectionPass;
@@ -684,25 +687,25 @@ proc symToClosure(n: PNode; owner: PSym; d: DetectionPass;
   let s = n.sym
   if s == owner:
     # recursive calls go through (lambda, hiddenParam):
-    let available = getHiddenParam(owner)
-    result = makeClosure(s, available.newSymNode, n.info)
+    let available = getHiddenParam(d.graph, owner)
+    result = makeClosure(d.graph, s, available.newSymNode, n.info)
   elif s.isIterator:
     result = closureCreationForIter(n, d, c)
   elif s.skipGenericOwner == owner:
     # direct dependency, so use the outer's env variable:
-    result = makeClosure(s, setupEnvVar(owner, d, c), n.info)
+    result = makeClosure(d.graph, s, setupEnvVar(owner, d, c), n.info)
   else:
-    let available = getHiddenParam(owner)
-    let wanted = getHiddenParam(s).typ
+    let available = getHiddenParam(d.graph, owner)
+    let wanted = getHiddenParam(d.graph, s).typ
     # ugh: call through some other inner proc;
     var access = newSymNode(available)
     while true:
       if access.typ == wanted:
-        return makeClosure(s, access, n.info)
+        return makeClosure(d.graph, s, access, n.info)
       let obj = access.typ.sons[0]
       let upField = lookupInRecord(obj.n, getIdent(upName))
       if upField == nil:
-        localError(n.info, "internal error: no environment found")
+        localError(d.graph.config, n.info, "internal error: no environment found")
         return n
       access = rawIndirectAccess(access, upField, n.info)
 
@@ -719,8 +722,8 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
         let oldInContainer = c.inContainer
         c.inContainer = 0
         var body = liftCapturedVars(s.getBody, s, d, c)
-        if oldIterTransf in c.features:
-          body = wrapIterBody(body, s)
+        if oldIterTransf in d.graph.config.features:
+          body = wrapIterBody(d.graph, body, s)
         if c.envvars.getOrDefault(s.id).isNil:
           s.ast.sons[bodyPos] = body
         else:
@@ -730,9 +733,9 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
         result = symToClosure(n, owner, d, c)
     elif s.id in d.capturedVars:
       if s.owner != owner:
-        result = accessViaEnvParam(n, owner)
+        result = accessViaEnvParam(d.graph, n, owner)
       elif owner.isIterator and interestingIterVar(s):
-        result = accessViaEnvParam(n, owner)
+        result = accessViaEnvParam(d.graph, n, owner)
       else:
         result = accessViaEnvVar(n, owner, d, c)
   of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom,
@@ -763,9 +766,9 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
       if n[1].kind == nkClosure: result = n[1]
   else:
     if owner.isIterator:
-      if oldIterTransf in c.features and n.kind == nkYieldStmt:
+      if oldIterTransf in d.graph.config.features and n.kind == nkYieldStmt:
         return transformYield(n, owner, d, c)
-      elif oldIterTransf in c.features and n.kind == nkReturnStmt:
+      elif oldIterTransf in d.graph.config.features and n.kind == nkReturnStmt:
         return transformReturn(n, owner, d, c)
       elif nfLL in n.flags:
         # special case 'when nimVm' due to bug #3636:
@@ -798,8 +801,8 @@ proc semCaptureSym*(s, owner: PSym) =
     # since the analysis is not entirely correct, we don't set 'tfCapturesEnv'
     # here
 
-proc liftIterToProc*(fn: PSym; body: PNode; ptrType: PType): PNode =
-  var d = initDetectionPass(fn)
+proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType): PNode =
+  var d = initDetectionPass(g, fn)
   var c = initLiftingPass(fn)
   # pretend 'fn' is a closure iterator for the analysis:
   let oldKind = fn.kind
@@ -808,11 +811,11 @@ proc liftIterToProc*(fn: PSym; body: PNode; ptrType: PType): PNode =
   fn.typ.callConv = ccClosure
   d.ownerToType[fn.id] = ptrType
   detectCapturedVars(body, fn, d)
-  result = wrapIterBody(liftCapturedVars(body, fn, d, c), fn)
+  result = wrapIterBody(g, liftCapturedVars(body, fn, d, c), fn)
   fn.kind = oldKind
   fn.typ.callConv = oldCC
 
-proc liftLambdas*(features: set[Feature], fn: PSym, body: PNode; tooEarly: var bool): PNode =
+proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool): PNode =
   # XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
   # the transformation even when compiling to JS ...
 
@@ -820,27 +823,26 @@ proc liftLambdas*(features: set[Feature], fn: PSym, body: PNode; tooEarly: var b
   let isCompileTime = sfCompileTime in fn.flags or fn.kind == skMacro
 
   if body.kind == nkEmpty or (
-      gCmd == cmdCompileToJS and not isCompileTime) or
+      g.config.cmd == cmdCompileToJS and not isCompileTime) or
       fn.skipGenericOwner.kind != skModule:
 
     # ignore forward declaration:
     result = body
     tooEarly = true
   else:
-    var d = initDetectionPass(fn)
+    var d = initDetectionPass(g, fn)
     detectCapturedVars(body, fn, d)
     if not d.somethingToDo and fn.isIterator:
       addClosureParam(d, fn, body.info)
       d.somethingToDo = true
     if d.somethingToDo:
       var c = initLiftingPass(fn)
-      c.features = features
       result = liftCapturedVars(body, fn, d, c)
       if c.envvars.getOrDefault(fn.id) != nil:
         result = newTree(nkStmtList, rawClosureCreation(fn, d, c), result)
 
-      if oldIterTransf in features:
-        result = wrapIterBody(result, fn)
+      if oldIterTransf in g.config.features:
+        result = wrapIterBody(g, result, fn)
     else:
       result = body
     #if fn.name.s == "get2":
@@ -848,15 +850,12 @@ proc liftLambdas*(features: set[Feature], fn: PSym, body: PNode; tooEarly: var b
     #  echo renderTree(result, {renderIds})
 
 proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
-  if body.kind == nkEmpty or gCmd == cmdCompileToJS:
-    result = body
-  else:
-    # XXX implement it properly
-    result = body
+  # XXX implement it properly
+  result = body
 
 # ------------------- iterator transformation --------------------------------
 
-proc liftForLoop*(body: PNode; owner: PSym): PNode =
+proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode =
   # problem ahead: the iterator could be invoked indirectly, but then
   # we don't know what environment to create here:
   #
@@ -885,10 +884,10 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
           break
         ...
     """
-  if liftingHarmful(owner): return body
+  if liftingHarmful(g.config, owner): return body
   var L = body.len
   if not (body.kind == nkForStmt and body[L-2].kind in nkCallKinds):
-    localError(body.info, "ignored invalid for loop")
+    localError(g.config, body.info, "ignored invalid for loop")
     return body
   var call = body[L-2]
 
@@ -901,7 +900,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
     # createClosure()
     let iter = op.sym
 
-    let hp = getHiddenParam(iter)
+    let hp = getHiddenParam(g, iter)
     env = newSym(skLet, iter.name, owner, body.info)
     env.typ = hp.typ
     env.flags = hp.flags
@@ -910,7 +909,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
     addVar(v, newSymNode(env))
     result.add(v)
     # add 'new' statement:
-    result.add(newCall(getSysSym"internalNew", env.newSymNode))
+    result.add(newCall(getSysSym(g, env.info, "internalNew"), env.newSymNode))
   elif op.kind == nkStmtListExpr:
     let closure = op.lastSon
     if closure.kind == nkClosure:
@@ -920,7 +919,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
 
   var loopBody = newNodeI(nkStmtList, body.info, 3)
   var whileLoop = newNodeI(nkWhileStmt, body.info, 2)
-  whileLoop.sons[0] = newIntTypeNode(nkIntLit, 1, getSysType(tyBool))
+  whileLoop.sons[0] = newIntTypeNode(nkIntLit, 1, getSysType(g, body.info, tyBool))
   whileLoop.sons[1] = loopBody
   result.add whileLoop
 
@@ -935,7 +934,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
 
   addSon(vpart, ast.emptyNode) # no explicit type
   if not env.isNil:
-    call.sons[0] = makeClosure(call.sons[0].sym, env.newSymNode, body.info)
+    call.sons[0] = makeClosure(g, call.sons[0].sym, env.newSymNode, body.info)
   addSon(vpart, call)
   addSon(v2, vpart)
 
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index a65587390..591561987 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -17,7 +17,7 @@
 
 import
   hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream,
-  wordrecg
+  wordrecg, configuration
 
 const
   MaxLineLength* = 80         # lines longer than this lead to a warning
@@ -131,7 +131,7 @@ type
                                 # like 0b01 or  r"\L" are unaffected
       commentOffsetA*, commentOffsetB*: int
 
-  TErrorHandler* = proc (info: TLineInfo; msg: TMsgKind; arg: string)
+  TErrorHandler* = proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string)
   TLexer* = object of TBaseLexer
     fileIdx*: FileIndex
     indentAhead*: int         # if > 0 an indendation has already been read
@@ -190,8 +190,8 @@ proc prettyTok*(tok: TToken): string =
   if isKeyword(tok.tokType): result = "keyword " & tok.ident.s
   else: result = tokToStr(tok)
 
-proc printTok*(tok: TToken) =
-  msgWriteln($tok.line & ":" & $tok.col & "\t" &
+proc printTok*(conf: ConfigRef; tok: TToken) =
+  msgWriteln(conf, $tok.line & ":" & $tok.col & "\t" &
       TokTypeToStr[tok.tokType] & " " & tokToStr(tok))
 
 proc initToken*(L: var TToken) =
@@ -234,7 +234,7 @@ proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream;
 
 proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream;
                 cache: IdentCache; config: ConfigRef) =
-  openLexer(lex, filename.fileInfoIdx, inputstream, cache, config)
+  openLexer(lex, fileInfoIdx(config, filename), inputstream, cache, config)
 
 proc closeLexer*(lex: var TLexer) =
   if lex.config != nil:
@@ -246,9 +246,9 @@ proc getLineInfo(L: TLexer): TLineInfo =
 
 proc dispMessage(L: TLexer; info: TLineInfo; msg: TMsgKind; arg: string) =
   if L.errorHandler.isNil:
-    msgs.message(info, msg, arg)
+    msgs.message(L.config, info, msg, arg)
   else:
-    L.errorHandler(info, msg, arg)
+    L.errorHandler(L.config, info, msg, arg)
 
 proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") =
   L.dispMessage(getLineInfo(L), msg, arg)
@@ -274,7 +274,7 @@ template tokenEnd(tok, pos) {.dirty.} =
   when defined(nimsuggest):
     let colB = getColNumber(L, pos)+1
     if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
-        L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}:
+        L.lineNumber == gTrackPos.line.int and L.config.ideCmd in {ideSug, ideCon}:
       L.cursor = CursorPosition.InToken
       gTrackPos.col = colA.int16
     colA = 0
@@ -285,7 +285,7 @@ template tokenEndIgnore(tok, pos) =
   when defined(nimsuggest):
     let colB = getColNumber(L, pos)
     if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
-        L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}:
+        L.lineNumber == gTrackPos.line.int and L.config.ideCmd in {ideSug, ideCon}:
       gTrackPos.fileIndex = trackPosInvalidFileIdx
       gTrackPos.line = 0'u16
     colA = 0
@@ -299,7 +299,7 @@ template tokenEndPrevious(tok, pos) =
     # the cursor in a string literal or comment:
     let colB = getColNumber(L, pos)
     if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
-        L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}:
+        L.lineNumber == gTrackPos.line.int and L.config.ideCmd in {ideSug, ideCon}:
       L.cursor = CursorPosition.BeforeToken
       gTrackPos = L.previousToken
       gTrackPosAttached = true
@@ -341,7 +341,8 @@ proc getNumber(L: var TLexer, result: var TToken) =
         break
       if buf[pos] == '_':
         if buf[pos+1] notin chars:
-          lexMessage(L, errInvalidToken, "_")
+          lexMessage(L, errGenerated,
+            "only single underscores may occur in a token: '__' is invalid")
           break
         add(tok.literal, '_')
         inc(pos)
@@ -355,7 +356,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
       inc(pos)
     L.bufpos = pos
 
-  proc lexMessageLitNum(L: var TLexer, msg: TMsgKind, startpos: int) =
+  proc lexMessageLitNum(L: var TLexer, msg: string, startpos: int) =
     # Used to get slightly human friendlier err messages.
     # Note: the erroneous 'O' char in the character set is intentional
     const literalishChars = {'A'..'F', 'a'..'f', '0'..'9', 'X', 'x', 'o', 'O',
@@ -376,7 +377,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
       add(t.literal, L.buf[L.bufpos])
       matchChars(L, t, {'0'..'9'})
     L.bufpos = msgPos
-    lexMessage(L, msg, t.literal)
+    lexMessage(L, errGenerated, msg % t.literal)
 
   var
     startpos, endpos: int
@@ -398,7 +399,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
     eatChar(L, result, '0')
     case L.buf[L.bufpos]
     of 'O':
-      lexMessageLitNum(L, errInvalidNumberOctalCode, startpos)
+      lexMessageLitNum(L, "$1 is not a valid number; did you mean octal? Then use one of '0o', '0c' or '0C'.", startpos)
     of 'x', 'X':
       eatChar(L, result, 'x')
       matchUnderscoreChars(L, result, {'0'..'9', 'a'..'f', 'A'..'F'})
@@ -409,7 +410,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
       eatChar(L, result, 'b')
       matchUnderscoreChars(L, result, {'0'..'1'})
     else:
-      internalError(getLineInfo(L), "getNumber")
+      internalError(L.config, getLineInfo(L), "getNumber")
   else:
     matchUnderscoreChars(L, result, {'0'..'9'})
     if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
@@ -464,7 +465,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
         result.tokType = tkInt8Lit
         inc(postPos)
       else:
-        lexMessageLitNum(L, errInvalidNumber, startpos)
+        lexMessageLitNum(L, "invalid number: '$1'", startpos)
     of 'u', 'U':
       inc(postPos)
       if (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'):
@@ -482,12 +483,12 @@ proc getNumber(L: var TLexer, result: var TToken) =
       else:
         result.tokType = tkUIntLit
     else:
-      lexMessageLitNum(L, errInvalidNumber, startpos)
+      lexMessageLitNum(L, "invalid number: '$1'", startpos)
 
   # Is there still a literalish char awaiting? Then it's an error!
   if  L.buf[postPos] in literalishChars or
      (L.buf[postPos] == '.' and L.buf[postPos + 1] in {'0'..'9'}):
-    lexMessageLitNum(L, errInvalidNumber, startpos)
+    lexMessageLitNum(L, "invalid number: '$1'", startpos)
 
   # Third stage, extract actual number
   L.bufpos = startpos            # restore position
@@ -528,7 +529,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
           else:
             break
       else:
-        internalError(getLineInfo(L), "getNumber")
+        internalError(L.config, getLineInfo(L), "getNumber")
 
       case result.tokType
       of tkIntLit, tkInt64Lit: result.iNumber = xi
@@ -545,7 +546,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
         # XXX: Test this on big endian machine!
       of tkFloat64Lit, tkFloatLit:
         result.fNumber = (cast[PFloat64](addr(xi)))[]
-      else: internalError(getLineInfo(L), "getNumber")
+      else: internalError(L.config, getLineInfo(L), "getNumber")
 
       # Bounds checks. Non decimal literals are allowed to overflow the range of
       # the datatype as long as their pattern don't overflow _bitwise_, hence
@@ -561,7 +562,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
 
         if outOfRange:
           #echo "out of range num: ", result.iNumber, " vs ", xi
-          lexMessageLitNum(L, errNumberOutOfRange, startpos)
+          lexMessageLitNum(L, "number out of range: '$1'", startpos)
 
     else:
       case result.tokType
@@ -590,7 +591,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
                         result.iNumber > BiggestInt(uint32.high))
         else: false
 
-      if outOfRange: lexMessageLitNum(L, errNumberOutOfRange, startpos)
+      if outOfRange: lexMessageLitNum(L, "number out of range: '$1'", startpos)
 
     # Promote int literal to int64? Not always necessary, but more consistent
     if result.tokType == tkIntLit:
@@ -598,9 +599,9 @@ proc getNumber(L: var TLexer, result: var TToken) =
         result.tokType = tkInt64Lit
 
   except ValueError:
-    lexMessageLitNum(L, errInvalidNumber, startpos)
+    lexMessageLitNum(L, "invalid number: '$1'", startpos)
   except OverflowError, RangeError:
-    lexMessageLitNum(L, errNumberOutOfRange, startpos)
+    lexMessageLitNum(L, "number out of range: '$1'", startpos)
   tokenEnd(result, postPos-1)
   L.bufpos = postPos
 
@@ -626,8 +627,9 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
   inc(L.bufpos)               # skip '\'
   case L.buf[L.bufpos]
   of 'n', 'N':
-    if gOldNewlines:
-      if tok.tokType == tkCharLit: lexMessage(L, errNnotAllowedInCharacter)
+    if L.config.oldNewlines:
+      if tok.tokType == tkCharLit:
+        lexMessage(L, errGenerated, "\\n not allowed in character literal")
       add(tok.literal, tnl)
     else:
       add(tok.literal, '\L')
@@ -696,8 +698,8 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
     var xi = 0
     handleDecChars(L, xi)
     if (xi <= 255): add(tok.literal, chr(xi))
-    else: lexMessage(L, errInvalidCharacterConstant)
-  else: lexMessage(L, errInvalidCharacterConstant)
+    else: lexMessage(L, errGenerated, "invalid character constant")
+  else: lexMessage(L, errGenerated, "invalid character constant")
 
 proc newString(s: cstring, len: int): string =
   ## XXX, how come there is no support for this?
@@ -712,7 +714,7 @@ proc handleCRLF(L: var TLexer, pos: int): int =
     if col > MaxLineLength:
       lexMessagePos(L, hintLineTooLong, pos)
 
-    if optEmbedOrigSrc in gGlobalOptions:
+    if optEmbedOrigSrc in L.config.globalOptions:
       let lineStart = cast[ByteAddress](L.buf) + L.lineStart
       let line = newString(cast[cstring](lineStart), col)
       addSourceLine(L.fileIdx, line)
@@ -761,7 +763,7 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
         tokenEndIgnore(tok, pos)
         var line2 = L.lineNumber
         L.lineNumber = line
-        lexMessagePos(L, errClosingTripleQuoteExpected, L.lineStart)
+        lexMessagePos(L, errGenerated, L.lineStart, "closing \"\"\" expected, but end of file reached")
         L.lineNumber = line2
         L.bufpos = pos
         break
@@ -784,7 +786,7 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
           break
       elif c in {CR, LF, nimlexbase.EndOfFile}:
         tokenEndIgnore(tok, pos)
-        lexMessage(L, errClosingQuoteExpected)
+        lexMessage(L, errGenerated, "closing \" expected")
         break
       elif (c == '\\') and not rawMode:
         L.bufpos = pos
@@ -800,12 +802,13 @@ proc getCharacter(L: var TLexer, tok: var TToken) =
   inc(L.bufpos)               # skip '
   var c = L.buf[L.bufpos]
   case c
-  of '\0'..pred(' '), '\'': lexMessage(L, errInvalidCharacterConstant)
+  of '\0'..pred(' '), '\'': lexMessage(L, errGenerated, "invalid character literal")
   of '\\': getEscapedChar(L, tok)
   else:
     tok.literal = $c
     inc(L.bufpos)
-  if L.buf[L.bufpos] != '\'': lexMessage(L, errMissingFinalQuote)
+  if L.buf[L.bufpos] != '\'':
+    lexMessage(L, errGenerated, "missing closing ' for character literal")
   tokenEndIgnore(tok, L.bufpos)
   inc(L.bufpos)               # skip '
 
@@ -826,7 +829,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
       inc(pos)
     of '_':
       if buf[pos+1] notin SymChars:
-        lexMessage(L, errInvalidToken, "_")
+        lexMessage(L, errGenerated, "invalid token: trailing underscore")
         break
       inc(pos)
     else: break
@@ -1014,7 +1017,7 @@ proc skip(L: var TLexer, tok: var TToken) =
       inc(pos)
       inc(tok.strongSpaceA)
     of '\t':
-      if not L.allowTabs: lexMessagePos(L, errTabulatorsAreNotAllowed, pos)
+      if not L.allowTabs: lexMessagePos(L, errGenerated, pos, "tabulators are not allowed")
       inc(pos)
     of CR, LF:
       tokenEndPrevious(tok, pos)
@@ -1119,7 +1122,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
         tok.tokType = tkParLe
         when defined(nimsuggest):
           if L.fileIdx == gTrackPos.fileIndex and tok.col < gTrackPos.col and
-                    tok.line == gTrackPos.line.int and gIdeCmd == ideCon:
+                    tok.line == gTrackPos.line.int and L.config.ideCmd == ideCon:
             gTrackPos.col = tok.col.int16
     of ')':
       tok.tokType = tkParRi
@@ -1140,7 +1143,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
     of '.':
       when defined(nimsuggest):
         if L.fileIdx == gTrackPos.fileIndex and tok.col+1 == gTrackPos.col and
-            tok.line == gTrackPos.line.int and gIdeCmd == ideSug:
+            tok.line == gTrackPos.line.int and L.config.ideCmd == ideSug:
           tok.tokType = tkDot
           L.cursor = CursorPosition.InToken
           gTrackPos.col = tok.col.int16
@@ -1182,7 +1185,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
       else:
         tok.literal = $c
         tok.tokType = tkInvalid
-        lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
+        lexMessage(L, errGenerated, "invalid token: " & c & " (\\" & $(ord(c)) & ')')
     of '\"':
       # check for extended raw string literal:
       var rawMode = L.bufpos > 0 and L.buf[L.bufpos-1] in SymChars
@@ -1199,7 +1202,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
       getNumber(L, tok)
       let c = L.buf[L.bufpos]
       if c in SymChars+{'_'}:
-        lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
+        lexMessage(L, errGenerated, "invalid token: no whitespace between number and identifier")
     else:
       if c in OpChars:
         getOperator(L, tok)
@@ -1209,6 +1212,6 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
       else:
         tok.literal = $c
         tok.tokType = tkInvalid
-        lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
+        lexMessage(L, errGenerated, "invalid token: " & c & " (\\" & $(ord(c)) & ')')
         inc(L.bufpos)
   atTokenEnd()
diff --git a/compiler/liftlocals.nim b/compiler/liftlocals.nim
index 3610a1486..4603d357b 100644
--- a/compiler/liftlocals.nim
+++ b/compiler/liftlocals.nim
@@ -52,17 +52,17 @@ proc lookupParam(params, dest: PNode): PSym =
     if params[i].kind == nkSym and params[i].sym.name.id == dest.ident.id:
       return params[i].sym
 
-proc liftLocalsIfRequested*(prc: PSym; n: PNode): PNode =
+proc liftLocalsIfRequested*(prc: PSym; n: PNode; conf: ConfigRef): PNode =
   let liftDest = getPragmaVal(prc.ast, wLiftLocals)
   if liftDest == nil: return n
   let partialParam = lookupParam(prc.typ.n, liftDest)
   if partialParam.isNil:
-    localError(liftDest.info, "'$1' is not a parameter of '$2'" %
+    localError(conf, liftDest.info, "'$1' is not a parameter of '$2'" %
               [$liftDest, prc.name.s])
     return n
   let objType = partialParam.typ.skipTypes(abstractPtrs)
   if objType.kind != tyObject or tfPartial notin objType.flags:
-    localError(liftDest.info, "parameter '$1' is not a pointer to a partial object" % $liftDest)
+    localError(conf, liftDest.info, "parameter '$1' is not a pointer to a partial object" % $liftDest)
     return n
   var c = Ctx(partialParam: partialParam, objType: objType)
   let w = newTree(nkStmtList, n)
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index e0d6e0098..b6d63d0bd 100644
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -11,23 +11,23 @@
 
 import
   intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread,
-  renderer, wordrecg, idgen, nimfix.prettybase
+  renderer, wordrecg, idgen, nimfix.prettybase, configuration, strutils
 
-proc ensureNoMissingOrUnusedSymbols(scope: PScope)
+proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope)
 
-proc noidentError(n, origin: PNode) =
+proc noidentError(conf: ConfigRef; n, origin: PNode) =
   var m = ""
   if origin != nil:
     m.add "in expression '" & origin.renderTree & "': "
   m.add "identifier expected, but found '" & n.renderTree & "'"
-  localError(n.info, m)
+  localError(conf, n.info, m)
 
-proc considerQuotedIdent*(n: PNode, origin: PNode = nil): PIdent =
+proc considerQuotedIdent*(conf: ConfigRef; n: PNode, origin: PNode = nil): PIdent =
   ## Retrieve a PIdent from a PNode, taking into account accent nodes.
   ## ``origin`` can be nil. If it is not nil, it is used for a better
   ## error message.
   template handleError(n, origin: PNode) =
-    noidentError(n, origin)
+    noidentError(conf, n, origin)
     result = getIdent"<Error>"
 
   case n.kind
@@ -36,7 +36,7 @@ proc considerQuotedIdent*(n: PNode, origin: PNode = nil): PIdent =
   of nkAccQuoted:
     case n.len
     of 0: handleError(n, origin)
-    of 1: result = considerQuotedIdent(n.sons[0], origin)
+    of 1: result = considerQuotedIdent(conf, n.sons[0], origin)
     else:
       var id = ""
       for i in 0..<n.len:
@@ -71,7 +71,7 @@ proc rawCloseScope*(c: PContext) =
   c.currentScope = c.currentScope.parent
 
 proc closeScope*(c: PContext) =
-  ensureNoMissingOrUnusedSymbols(c.currentScope)
+  ensureNoMissingOrUnusedSymbols(c, c.currentScope)
   rawCloseScope(c)
 
 iterator walkScopes*(scope: PScope): PScope =
@@ -80,15 +80,15 @@ iterator walkScopes*(scope: PScope): PScope =
     yield current
     current = current.parent
 
-proc skipAlias*(s: PSym; n: PNode): PSym =
+proc skipAlias*(s: PSym; n: PNode; conf: ConfigRef): PSym =
   if s == nil or s.kind != skAlias:
     result = s
   else:
     result = s.owner
-    if gCmd == cmdPretty:
+    if conf.cmd == cmdPretty:
       prettybase.replaceDeprecated(n.info, s, result)
     else:
-      message(n.info, warnDeprecated, "use " & result.name.s & " instead; " &
+      message(conf, n.info, warnDeprecated, "use " & result.name.s & " instead; " &
               s.name.s)
 
 proc localSearchInScope*(c: PContext, s: PIdent): PSym =
@@ -125,14 +125,14 @@ proc errorSym*(c: PContext, n: PNode): PSym =
   # ensure that 'considerQuotedIdent' can't fail:
   if m.kind == nkDotExpr: m = m.sons[1]
   let ident = if m.kind in {nkIdent, nkSym, nkAccQuoted}:
-      considerQuotedIdent(m)
+      considerQuotedIdent(c.config, m)
     else:
       getIdent("err:" & renderTree(m))
-  result = newSym(skError, ident, getCurrOwner(c), n.info)
+  result = newSym(skError, ident, getCurrOwner(c), n.info, {})
   result.typ = errorType(c)
   incl(result.flags, sfDiscardable)
   # pretend it's imported from some unknown module to prevent cascading errors:
-  if gCmd != cmdInteractive and c.compilesContextId == 0:
+  if c.config.cmd != cmdInteractive and c.compilesContextId == 0:
     c.importTable.addSym(result)
 
 type
@@ -154,7 +154,7 @@ proc getSymRepr*(s: PSym): string =
   else:
     result = s.name.s
 
-proc ensureNoMissingOrUnusedSymbols(scope: PScope) =
+proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) =
   # check if all symbols have been used and defined:
   var it: TTabIter
   var s = initTabIter(it, scope.symbols)
@@ -164,54 +164,53 @@ proc ensureNoMissingOrUnusedSymbols(scope: PScope) =
       # too many 'implementation of X' errors are annoying
       # and slow 'suggest' down:
       if missingImpls == 0:
-        localError(s.info, errImplOfXexpected, getSymRepr(s))
+        localError(c.config, s.info, "implementation of '$1' expected" % getSymRepr(s))
       inc missingImpls
     elif {sfUsed, sfExported} * s.flags == {} and optHints in s.options:
-      # BUGFIX: check options in s!
       if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}:
         # XXX: implicit type params are currently skTypes
         # maybe they can be made skGenericParam as well.
         if s.typ != nil and tfImplicitTypeParam notin s.typ.flags and
            s.typ.kind != tyGenericParam:
-          message(s.info, hintXDeclaredButNotUsed, getSymRepr(s))
+          message(c.config, s.info, hintXDeclaredButNotUsed, getSymRepr(s))
     s = nextIter(it, scope.symbols)
 
-proc wrongRedefinition*(info: TLineInfo, s: string) =
-  if gCmd != cmdInteractive:
-    localError(info, errAttemptToRedefine, s)
+proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string) =
+  if c.config.cmd != cmdInteractive:
+    localError(c.config, info, "redefinition of '$1'" % s)
 
 proc addDecl*(c: PContext, sym: PSym, info: TLineInfo) =
   if not c.currentScope.addUniqueSym(sym):
-    wrongRedefinition(info, sym.name.s)
+    wrongRedefinition(c, info, sym.name.s)
 
 proc addDecl*(c: PContext, sym: PSym) =
   if not c.currentScope.addUniqueSym(sym):
-    wrongRedefinition(sym.info, sym.name.s)
+    wrongRedefinition(c, sym.info, sym.name.s)
 
 proc addPrelimDecl*(c: PContext, sym: PSym) =
   discard c.currentScope.addUniqueSym(sym)
 
-proc addDeclAt*(scope: PScope, sym: PSym) =
+proc addDeclAt*(c: PContext; scope: PScope, sym: PSym) =
   if not scope.addUniqueSym(sym):
-    wrongRedefinition(sym.info, sym.name.s)
+    wrongRedefinition(c, sym.info, sym.name.s)
 
 proc addInterfaceDeclAux(c: PContext, sym: PSym) =
   if sfExported in sym.flags:
     # add to interface:
     if c.module != nil: strTableAdd(c.module.tab, sym)
-    else: internalError(sym.info, "addInterfaceDeclAux")
+    else: internalError(c.config, sym.info, "addInterfaceDeclAux")
 
 proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) =
-  addDeclAt(scope, sym)
+  addDeclAt(c, scope, sym)
   addInterfaceDeclAux(c, sym)
 
-proc addOverloadableSymAt*(scope: PScope, fn: PSym) =
+proc addOverloadableSymAt*(c: PContext; scope: PScope, fn: PSym) =
   if fn.kind notin OverloadableSyms:
-    internalError(fn.info, "addOverloadableSymAt")
+    internalError(c.config, fn.info, "addOverloadableSymAt")
     return
   let check = strTableGet(scope.symbols, fn.name)
   if check != nil and check.kind notin OverloadableSyms:
-    wrongRedefinition(fn.info, fn.name.s)
+    wrongRedefinition(c, fn.info, fn.name.s)
   else:
     scope.addSym(fn)
 
@@ -222,12 +221,10 @@ proc addInterfaceDecl*(c: PContext, sym: PSym) =
 
 proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) =
   # it adds the symbol to the interface if appropriate
-  addOverloadableSymAt(scope, sym)
+  addOverloadableSymAt(c, scope, sym)
   addInterfaceDeclAux(c, sym)
 
 when defined(nimfix):
-  import strutils
-
   # when we cannot find the identifier, retry with a changed identifer:
   proc altSpelling(x: PIdent): PIdent =
     case x.s[0]
@@ -255,7 +252,7 @@ proc errorUseQualifier*(c: PContext; info: TLineInfo; s: PSym) =
     err.add candidate.owner.name.s & "." & candidate.name.s
     candidate = nextIdentIter(ti, c.importTable.symbols)
     inc i
-  localError(info, errGenerated, err)
+  localError(c.config, info, errGenerated, err)
 
 proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string) =
   var err = "undeclared identifier: '" & name & "'"
@@ -264,13 +261,13 @@ proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string) =
     err.add c.recursiveDep
     # prevent excessive errors for 'nim check'
     c.recursiveDep = nil
-  localError(info, errGenerated, err)
+  localError(c.config, info, errGenerated, err)
 
 proc lookUp*(c: PContext, n: PNode): PSym =
   # Looks up a symbol. Generates an error in case of nil.
   case n.kind
   of nkIdent:
-    result = searchInScopes(c, n.ident).skipAlias(n)
+    result = searchInScopes(c, n.ident).skipAlias(n, c.config)
     if result == nil:
       fixSpelling(n, n.ident, searchInScopes)
       errorUndeclaredIdentifier(c, n.info, n.ident.s)
@@ -278,14 +275,14 @@ proc lookUp*(c: PContext, n: PNode): PSym =
   of nkSym:
     result = n.sym
   of nkAccQuoted:
-    var ident = considerQuotedIdent(n)
-    result = searchInScopes(c, ident).skipAlias(n)
+    var ident = considerQuotedIdent(c.config, n)
+    result = searchInScopes(c, ident).skipAlias(n, c.config)
     if result == nil:
       fixSpelling(n, ident, searchInScopes)
       errorUndeclaredIdentifier(c, n.info, ident.s)
       result = errorSym(c, n)
   else:
-    internalError(n.info, "lookUp")
+    internalError(c.config, n.info, "lookUp")
     return
   if contains(c.ambiguousSymbols, result.id):
     errorUseQualifier(c, n.info, result)
@@ -299,11 +296,11 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
   const allExceptModule = {low(TSymKind)..high(TSymKind)}-{skModule,skPackage}
   case n.kind
   of nkIdent, nkAccQuoted:
-    var ident = considerQuotedIdent(n)
+    var ident = considerQuotedIdent(c.config, n)
     if checkModule in flags:
-      result = searchInScopes(c, ident).skipAlias(n)
+      result = searchInScopes(c, ident).skipAlias(n, c.config)
     else:
-      result = searchInScopes(c, ident, allExceptModule).skipAlias(n)
+      result = searchInScopes(c, ident, allExceptModule).skipAlias(n, c.config)
     if result == nil and checkPureEnumFields in flags:
       result = strTableGet(c.pureEnumFields, ident)
     if result == nil and checkUndeclared in flags:
@@ -325,12 +322,12 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
       if n.sons[1].kind == nkIdent:
         ident = n.sons[1].ident
       elif n.sons[1].kind == nkAccQuoted:
-        ident = considerQuotedIdent(n.sons[1])
+        ident = considerQuotedIdent(c.config, n.sons[1])
       if ident != nil:
         if m == c.module:
-          result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n)
+          result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n, c.config)
         else:
-          result = strTableGet(m.tab, ident).skipAlias(n)
+          result = strTableGet(m.tab, ident).skipAlias(n, c.config)
         if result == nil and checkUndeclared in flags:
           fixSpelling(n.sons[1], ident, searchInScopes)
           errorUndeclaredIdentifier(c, n.sons[1].info, ident.s)
@@ -339,7 +336,7 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
         result = n.sons[1].sym
       elif checkUndeclared in flags and
            n.sons[1].kind notin {nkOpenSymChoice, nkClosedSymChoice}:
-        localError(n.sons[1].info, errIdentifierExpected,
+        localError(c.config, n.sons[1].info, "identifier expected, but got: " &
                    renderTree(n.sons[1]))
         result = errorSym(c, n.sons[1])
   else:
@@ -349,11 +346,11 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
 proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
   case n.kind
   of nkIdent, nkAccQuoted:
-    var ident = considerQuotedIdent(n)
+    var ident = considerQuotedIdent(c.config, n)
     o.scope = c.currentScope
     o.mode = oimNoQualifier
     while true:
-      result = initIdentIter(o.it, o.scope.symbols, ident).skipAlias(n)
+      result = initIdentIter(o.it, o.scope.symbols, ident).skipAlias(n, c.config)
       if result != nil:
         break
       else:
@@ -370,17 +367,17 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
       if n.sons[1].kind == nkIdent:
         ident = n.sons[1].ident
       elif n.sons[1].kind == nkAccQuoted:
-        ident = considerQuotedIdent(n.sons[1], n)
+        ident = considerQuotedIdent(c.config, n.sons[1], n)
       if ident != nil:
         if o.m == c.module:
           # a module may access its private members:
           result = initIdentIter(o.it, c.topLevelScope.symbols,
-                                 ident).skipAlias(n)
+                                 ident).skipAlias(n, c.config)
           o.mode = oimSelfModule
         else:
-          result = initIdentIter(o.it, o.m.tab, ident).skipAlias(n)
+          result = initIdentIter(o.it, o.m.tab, ident).skipAlias(n, c.config)
       else:
-        noidentError(n.sons[1], n)
+        noidentError(c.config, n.sons[1], n)
         result = errorSym(c, n.sons[1])
   of nkClosedSymChoice, nkOpenSymChoice:
     o.mode = oimSymChoice
@@ -408,18 +405,18 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
     result = nil
   of oimNoQualifier:
     if o.scope != nil:
-      result = nextIdentIter(o.it, o.scope.symbols).skipAlias(n)
+      result = nextIdentIter(o.it, o.scope.symbols).skipAlias(n, c.config)
       while result == nil:
         o.scope = o.scope.parent
         if o.scope == nil: break
-        result = initIdentIter(o.it, o.scope.symbols, o.it.name).skipAlias(n)
+        result = initIdentIter(o.it, o.scope.symbols, o.it.name).skipAlias(n, c.config)
         # BUGFIX: o.it.name <-> n.ident
     else:
       result = nil
   of oimSelfModule:
-    result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n)
+    result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n, c.config)
   of oimOtherModule:
-    result = nextIdentIter(o.it, o.m.tab).skipAlias(n)
+    result = nextIdentIter(o.it, o.m.tab).skipAlias(n, c.config)
   of oimSymChoice:
     if o.symChoiceIndex < sonsLen(n):
       result = n.sons[o.symChoiceIndex].sym
@@ -430,19 +427,19 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
       o.mode = oimSymChoiceLocalLookup
       o.scope = c.currentScope
       result = firstIdentExcluding(o.it, o.scope.symbols,
-                                   n.sons[0].sym.name, o.inSymChoice).skipAlias(n)
+                                   n.sons[0].sym.name, o.inSymChoice).skipAlias(n, c.config)
       while result == nil:
         o.scope = o.scope.parent
         if o.scope == nil: break
         result = firstIdentExcluding(o.it, o.scope.symbols,
-                                     n.sons[0].sym.name, o.inSymChoice).skipAlias(n)
+                                     n.sons[0].sym.name, o.inSymChoice).skipAlias(n, c.config)
   of oimSymChoiceLocalLookup:
-    result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice).skipAlias(n)
+    result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice).skipAlias(n, c.config)
     while result == nil:
       o.scope = o.scope.parent
       if o.scope == nil: break
       result = firstIdentExcluding(o.it, o.scope.symbols,
-                                   n.sons[0].sym.name, o.inSymChoice).skipAlias(n)
+                                   n.sons[0].sym.name, o.inSymChoice).skipAlias(n, c.config)
 
   if result != nil and result.kind == skStub: loadStub(result)
 
diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim
index 8510bf7ee..13336f00e 100644
--- a/compiler/lowerings.nim
+++ b/compiler/lowerings.nim
@@ -12,18 +12,18 @@
 const
   genPrefix* = ":tmp"         # prefix for generated names
 
-import ast, astalgo, types, idents, magicsys, msgs, options
+import ast, astalgo, types, idents, magicsys, msgs, options, modulegraphs
 from trees import getMagic
 
 proc newDeref*(n: PNode): PNode {.inline.} =
   result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
   addSon(result, n)
 
-proc newTupleAccess*(tup: PNode, i: int): PNode =
+proc newTupleAccess*(g: ModuleGraph; tup: PNode, i: int): PNode =
   result = newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(
                      abstractInst).sons[i])
   addSon(result, copyTree(tup))
-  var lit = newNodeIT(nkIntLit, tup.info, getSysType(tyInt))
+  var lit = newNodeIT(nkIntLit, tup.info, getSysType(g, tup.info, tyInt))
   lit.intVal = i
   addSon(result, lit)
 
@@ -44,12 +44,12 @@ proc newFastAsgnStmt(le, ri: PNode): PNode =
   result.sons[0] = le
   result.sons[1] = ri
 
-proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
+proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
   assert n.kind == nkVarTuple
   let value = n.lastSon
   result = newNodeI(nkStmtList, n.info)
 
-  var temp = newSym(skTemp, getIdent(genPrefix), owner, value.info)
+  var temp = newSym(skTemp, getIdent(genPrefix), owner, value.info, g.config.options)
   temp.typ = skipTypes(value.typ, abstractInst)
   incl(temp.flags, sfFromGeneric)
 
@@ -61,7 +61,7 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
   result.add newAsgnStmt(tempAsNode, value)
   for i in 0 .. n.len-3:
     if n.sons[i].kind == nkSym: v.addVar(n.sons[i])
-    result.add newAsgnStmt(n.sons[i], newTupleAccess(tempAsNode, i))
+    result.add newAsgnStmt(n.sons[i], newTupleAccess(g, tempAsNode, i))
 
 proc newTupleAccessRaw*(tup: PNode, i: int): PNode =
   result = newNodeI(nkBracketExpr, tup.info)
@@ -77,7 +77,7 @@ proc lowerTupleUnpackingForAsgn*(n: PNode; owner: PSym): PNode =
   let value = n.lastSon
   result = newNodeI(nkStmtList, n.info)
 
-  var temp = newSym(skLet, getIdent("_"), owner, value.info)
+  var temp = newSym(skLet, getIdent("_"), owner, value.info, owner.options)
   var v = newNodeI(nkLetSection, value.info)
   let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info)
 
@@ -95,7 +95,7 @@ proc lowerTupleUnpackingForAsgn*(n: PNode; owner: PSym): PNode =
 proc lowerSwap*(n: PNode; owner: PSym): PNode =
   result = newNodeI(nkStmtList, n.info)
   # note: cannot use 'skTemp' here cause we really need the copy for the VM :-(
-  var temp = newSym(skVar, getIdent(genPrefix), owner, n.info)
+  var temp = newSym(skVar, getIdent(genPrefix), owner, n.info, owner.options)
   temp.typ = n.sons[1].typ
   incl(temp.flags, sfFromGeneric)
 
@@ -112,16 +112,16 @@ proc lowerSwap*(n: PNode; owner: PSym): PNode =
   result.add newFastAsgnStmt(n[1], n[2])
   result.add newFastAsgnStmt(n[2], tempAsNode)
 
-proc createObj*(owner: PSym, info: TLineInfo; final=true): PType =
+proc createObj*(g: ModuleGraph; owner: PSym, info: TLineInfo; final=true): PType =
   result = newType(tyObject, owner)
   if final:
     rawAddSon(result, nil)
     incl result.flags, tfFinal
   else:
-    rawAddSon(result, getCompilerProc("RootObj").typ)
+    rawAddSon(result, getCompilerProc(g, "RootObj").typ)
   result.n = newNodeI(nkRecList, info)
   let s = newSym(skType, getIdent("Env_" & info.toFilename),
-                  owner, info)
+                  owner, info, owner.options)
   incl s.flags, sfAnon
   s.typ = result
   result.sym = s
@@ -174,7 +174,8 @@ proc lookupInRecord(n: PNode, id: int): PSym =
 proc addField*(obj: PType; s: PSym) =
   # because of 'gensym' support, we have to mangle the name with its ID.
   # This is hacky but the clean solution is much more complex than it looks.
-  var field = newSym(skField, getIdent(s.name.s & $obj.n.len), s.owner, s.info)
+  var field = newSym(skField, getIdent(s.name.s & $obj.n.len), s.owner, s.info,
+                     s.options)
   field.id = -s.id
   let t = skipIntLit(s.typ)
   field.typ = t
@@ -185,7 +186,8 @@ proc addField*(obj: PType; s: PSym) =
 proc addUniqueField*(obj: PType; s: PSym): PSym {.discardable.} =
   result = lookupInRecord(obj.n, s.id)
   if result == nil:
-    var field = newSym(skField, getIdent(s.name.s & $obj.n.len), s.owner, s.info)
+    var field = newSym(skField, getIdent(s.name.s & $obj.n.len), s.owner, s.info,
+                       s.options)
     field.id = -s.id
     let t = skipIntLit(s.typ)
     field.typ = t
@@ -218,7 +220,7 @@ proc indirectAccess*(a: PNode, b: int, info: TLineInfo): PNode =
   #if field == nil:
   #  echo "FIELD ", b
   #  debug deref.typ
-  internalAssert field != nil
+  assert field != nil
   addSon(deref, a)
   result = newNodeI(nkDotExpr, info)
   addSon(result, deref)
@@ -242,7 +244,7 @@ proc indirectAccess(a: PNode, b: string, info: TLineInfo): PNode =
   #if field == nil:
   #  echo "FIELD ", b
   #  debug deref.typ
-  internalAssert field != nil
+  assert field != nil
   addSon(deref, a)
   result = newNodeI(nkDotExpr, info)
   addSon(result, deref)
@@ -278,12 +280,12 @@ proc genDeref*(n: PNode): PNode =
                      n.typ.skipTypes(abstractInst).sons[0])
   result.add n
 
-proc callCodegenProc*(name: string, arg1: PNode;
+proc callCodegenProc*(g: ModuleGraph; name: string, arg1: PNode;
                       arg2, arg3, optionalArgs: PNode = nil): PNode =
   result = newNodeI(nkCall, arg1.info)
-  let sym = magicsys.getCompilerProc(name)
+  let sym = magicsys.getCompilerProc(g, name)
   if sym == nil:
-    localError(arg1.info, errSystemNeeds, name)
+    localError(g.config, arg1.info, "system module needs: " & name)
   else:
     result.add newSymNode(sym)
     result.add arg1
@@ -333,9 +335,10 @@ proc typeNeedsNoDeepCopy(t: PType): bool =
   if t.kind in {tyVar, tyLent, tySequence}: t = t.lastSon
   result = not containsGarbageCollectedRef(t)
 
-proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType;
+proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; owner: PSym; typ: PType;
                  v: PNode; useShallowCopy=false): PSym =
-  result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info)
+  result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info,
+                  owner.options)
   result.typ = typ
   incl(result.flags, sfFromGeneric)
 
@@ -349,7 +352,7 @@ proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType;
       varInit.add newFastAsgnStmt(newSymNode(result), v)
     else:
       let deepCopyCall = newNodeI(nkCall, varInit.info, 3)
-      deepCopyCall.sons[0] = newSymNode(getSysMagic("deepCopy", mDeepCopy))
+      deepCopyCall.sons[0] = newSymNode(getSysMagic(g, varSection.info, "deepCopy", mDeepCopy))
       deepCopyCall.sons[1] = newSymNode(result)
       deepCopyCall.sons[2] = v
       varInit.add deepCopyCall
@@ -384,23 +387,23 @@ stmtList:
 
 """
 
-proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
+proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
                        varSection, varInit, call, barrier, fv: PNode;
                        spawnKind: TSpawnResult): PSym =
   var body = newNodeI(nkStmtList, f.info)
   var threadLocalBarrier: PSym
   if barrier != nil:
     var varSection2 = newNodeI(nkVarSection, barrier.info)
-    threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner,
+    threadLocalBarrier = addLocalVar(g, varSection2, nil, argsParam.owner,
                                      barrier.typ, barrier)
     body.add varSection2
-    body.add callCodegenProc("barrierEnter", threadLocalBarrier.newSymNode)
+    body.add callCodegenProc(g, "barrierEnter", threadLocalBarrier.newSymNode)
   var threadLocalProm: PSym
   if spawnKind == srByVar:
-    threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv)
+    threadLocalProm = addLocalVar(g, varSection, nil, argsParam.owner, fv.typ, fv)
   elif fv != nil:
-    internalAssert fv.typ.kind == tyGenericInst
-    threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv)
+    internalAssert g.config, fv.typ.kind == tyGenericInst
+    threadLocalProm = addLocalVar(g, varSection, nil, argsParam.owner, fv.typ, fv)
   body.add varSection
   body.add varInit
   if fv != nil and spawnKind != srByVar:
@@ -409,30 +412,30 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
     body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
       "owner", fv.info), threadParam.newSymNode)
 
-  body.add callCodegenProc("nimArgsPassingDone", threadParam.newSymNode)
+  body.add callCodegenProc(g, "nimArgsPassingDone", threadParam.newSymNode)
   if spawnKind == srByVar:
     body.add newAsgnStmt(genDeref(threadLocalProm.newSymNode), call)
   elif fv != nil:
     let fk = fv.typ.sons[1].flowVarKind
     if fk == fvInvalid:
-      localError(f.info, "cannot create a flowVar of type: " &
+      localError(g.config, f.info, "cannot create a flowVar of type: " &
         typeToString(fv.typ.sons[1]))
     body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
       if fk == fvGC: "data" else: "blob", fv.info), call)
     if fk == fvGC:
       let incRefCall = newNodeI(nkCall, fv.info, 2)
-      incRefCall.sons[0] = newSymNode(getSysMagic("GCref", mGCref))
+      incRefCall.sons[0] = newSymNode(getSysMagic(g, fv.info, "GCref", mGCref))
       incRefCall.sons[1] = indirectAccess(threadLocalProm.newSymNode,
                                           "data", fv.info)
       body.add incRefCall
     if barrier == nil:
       # by now 'fv' is shared and thus might have beeen overwritten! we need
       # to use the thread-local view instead:
-      body.add callCodegenProc("nimFlowVarSignal", threadLocalProm.newSymNode)
+      body.add callCodegenProc(g, "nimFlowVarSignal", threadLocalProm.newSymNode)
   else:
     body.add call
   if barrier != nil:
-    body.add callCodegenProc("barrierLeave", threadLocalBarrier.newSymNode)
+    body.add callCodegenProc(g, "barrierLeave", threadLocalBarrier.newSymNode)
 
   var params = newNodeI(nkFormalParams, f.info)
   params.add emptyNode
@@ -449,7 +452,8 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
   t.n.add argsParam.newSymNode
 
   let name = (if f.kind == nkSym: f.sym.name.s else: genPrefix) & "Wrapper"
-  result = newSym(skProc, getIdent(name), argsParam.owner, f.info)
+  result = newSym(skProc, getIdent(name), argsParam.owner, f.info,
+                  argsParam.options)
   result.ast = newProcNode(nkProcDef, f.info, body, params, newSymNode(result))
   result.typ = t
 
@@ -460,7 +464,7 @@ proc createCastExpr(argsParam: PSym; objType: PType): PNode =
   result.typ = newType(tyPtr, objType.owner)
   result.typ.rawAddSon(objType)
 
-proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym,
+proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; scratchObj: PSym,
                              castExpr, call,
                              varSection, varInit, result: PNode) =
   let formals = n[0].typ.n
@@ -470,17 +474,17 @@ proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym,
     # 'tyOpenArray':
     var argType = n[i].typ.skipTypes(abstractInst)
     if i < formals.len and formals[i].typ.kind in {tyVar, tyLent}:
-      localError(n[i].info, "'spawn'ed function cannot have a 'var' parameter")
+      localError(g.config, n[i].info, "'spawn'ed function cannot have a 'var' parameter")
     #elif containsTyRef(argType):
     #  localError(n[i].info, "'spawn'ed function cannot refer to 'ref'/closure")
 
     let fieldname = if i < formals.len: formals[i].sym.name else: tmpName
-    var field = newSym(skField, fieldname, objType.owner, n.info)
+    var field = newSym(skField, fieldname, objType.owner, n.info, g.config.options)
     field.typ = argType
     objType.addField(field)
     result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i])
 
-    let temp = addLocalVar(varSection, varInit, objType.owner, argType,
+    let temp = addLocalVar(g, varSection, varInit, objType.owner, argType,
                            indirectAccess(castExpr, field, n.info))
     call.add(newSymNode(temp))
 
@@ -501,20 +505,20 @@ proc getRoot*(n: PNode): PSym =
     if getMagic(n) == mSlice: result = getRoot(n.sons[1])
   else: discard
 
-proc newIntLit*(value: BiggestInt): PNode =
+proc newIntLit*(g: ModuleGraph; info: TLineInfo; value: BiggestInt): PNode =
   result = nkIntLit.newIntNode(value)
-  result.typ = getSysType(tyInt)
+  result.typ = getSysType(g, info, tyInt)
 
-proc genHigh*(n: PNode): PNode =
+proc genHigh*(g: ModuleGraph; n: PNode): PNode =
   if skipTypes(n.typ, abstractVar).kind == tyArray:
-    result = newIntLit(lastOrd(skipTypes(n.typ, abstractVar)))
+    result = newIntLit(g, n.info, lastOrd(skipTypes(n.typ, abstractVar)))
   else:
     result = newNodeI(nkCall, n.info, 2)
-    result.typ = getSysType(tyInt)
-    result.sons[0] = newSymNode(getSysMagic("high", mHigh))
+    result.typ = getSysType(g, n.info, tyInt)
+    result.sons[0] = newSymNode(getSysMagic(g, n.info, "high", mHigh))
     result.sons[1] = n
 
-proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
+proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchObj: PSym;
                              castExpr, call,
                              varSection, varInit, result: PNode) =
   let formals = n[0].typ.n
@@ -529,16 +533,16 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
     #  localError(n.info, "'spawn'ed function cannot refer to 'ref'/closure")
 
     let fieldname = if i < formals.len: formals[i].sym.name else: tmpName
-    var field = newSym(skField, fieldname, objType.owner, n.info)
+    var field = newSym(skField, fieldname, objType.owner, n.info, g.config.options)
 
     if argType.kind in {tyVarargs, tyOpenArray}:
       # important special case: we always create a zero-copy slice:
       let slice = newNodeI(nkCall, n.info, 4)
       slice.typ = n.typ
-      slice.sons[0] = newSymNode(createMagic("slice", mSlice))
-      slice.sons[0].typ = getSysType(tyInt) # fake type
-      var fieldB = newSym(skField, tmpName, objType.owner, n.info)
-      fieldB.typ = getSysType(tyInt)
+      slice.sons[0] = newSymNode(createMagic(g, "slice", mSlice))
+      slice.sons[0].typ = getSysType(g, n.info, tyInt) # fake type
+      var fieldB = newSym(skField, tmpName, objType.owner, n.info, g.config.options)
+      fieldB.typ = getSysType(g, n.info, tyInt)
       objType.addField(fieldB)
 
       if getMagic(n) == mSlice:
@@ -547,13 +551,13 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
         objType.addField(field)
         result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
 
-        var fieldA = newSym(skField, tmpName, objType.owner, n.info)
-        fieldA.typ = getSysType(tyInt)
+        var fieldA = newSym(skField, tmpName, objType.owner, n.info, g.config.options)
+        fieldA.typ = getSysType(g, n.info, tyInt)
         objType.addField(fieldA)
         result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldA), n[2])
         result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3])
 
-        let threadLocal = addLocalVar(varSection,nil, objType.owner, fieldA.typ,
+        let threadLocal = addLocalVar(g, varSection,nil, objType.owner, fieldA.typ,
                                       indirectAccess(castExpr, fieldA, n.info),
                                       useShallowCopy=true)
         slice.sons[2] = threadLocal.newSymNode
@@ -562,13 +566,13 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
         field.typ = a.typ
         objType.addField(field)
         result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
-        result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), genHigh(n))
+        result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), genHigh(g, n))
 
-        slice.sons[2] = newIntLit(0)
+        slice.sons[2] = newIntLit(g, n.info, 0)
       # the array itself does not need to go through a thread local variable:
       slice.sons[1] = genDeref(indirectAccess(castExpr, field, n.info))
 
-      let threadLocal = addLocalVar(varSection,nil, objType.owner, fieldB.typ,
+      let threadLocal = addLocalVar(g, varSection,nil, objType.owner, fieldB.typ,
                                     indirectAccess(castExpr, fieldB, n.info),
                                     useShallowCopy=true)
       slice.sons[3] = threadLocal.newSymNode
@@ -580,7 +584,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
       field.typ = a.typ
       objType.addField(field)
       result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
-      let threadLocal = addLocalVar(varSection,nil, objType.owner, field.typ,
+      let threadLocal = addLocalVar(g, varSection,nil, objType.owner, field.typ,
                                     indirectAccess(castExpr, field, n.info),
                                     useShallowCopy=true)
       call.add(genDeref(threadLocal.newSymNode))
@@ -589,13 +593,13 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
       field.typ = argType
       objType.addField(field)
       result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n)
-      let threadLocal = addLocalVar(varSection, varInit,
+      let threadLocal = addLocalVar(g, varSection, varInit,
                                     objType.owner, field.typ,
                                     indirectAccess(castExpr, field, n.info),
                                     useShallowCopy=true)
       call.add(threadLocal.newSymNode)
 
-proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
+proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: PType;
                        barrier, dest: PNode = nil): PNode =
   # if 'barrier' != nil, then it is in a 'parallel' section and we
   # generate quite different code
@@ -603,35 +607,35 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
   let spawnKind = spawnResult(retType, barrier!=nil)
   case spawnKind
   of srVoid:
-    internalAssert dest == nil
+    internalAssert g.config, dest == nil
     result = newNodeI(nkStmtList, n.info)
   of srFlowVar:
-    internalAssert dest == nil
+    internalAssert g.config, dest == nil
     result = newNodeIT(nkStmtListExpr, n.info, retType)
   of srByVar:
-    if dest == nil: localError(n.info, "'spawn' must not be discarded")
+    if dest == nil: localError(g.config, n.info, "'spawn' must not be discarded")
     result = newNodeI(nkStmtList, n.info)
 
   if n.kind notin nkCallKinds:
-    localError(n.info, "'spawn' takes a call expression")
+    localError(g.config, n.info, "'spawn' takes a call expression")
     return
-  if optThreadAnalysis in gGlobalOptions:
+  if optThreadAnalysis in g.config.globalOptions:
     if {tfThread, tfNoSideEffect} * n[0].typ.flags == {}:
-      localError(n.info, "'spawn' takes a GC safe call expression")
+      localError(g.config, n.info, "'spawn' takes a GC safe call expression")
   var
-    threadParam = newSym(skParam, getIdent"thread", owner, n.info)
-    argsParam = newSym(skParam, getIdent"args", owner, n.info)
+    threadParam = newSym(skParam, getIdent"thread", owner, n.info, g.config.options)
+    argsParam = newSym(skParam, getIdent"args", owner, n.info, g.config.options)
   block:
-    let ptrType = getSysType(tyPointer)
+    let ptrType = getSysType(g, n.info, tyPointer)
     threadParam.typ = ptrType
     argsParam.typ = ptrType
     argsParam.position = 1
 
-  var objType = createObj(owner, n.info)
+  var objType = createObj(g, owner, n.info)
   incl(objType.flags, tfFinal)
   let castExpr = createCastExpr(argsParam, objType)
 
-  var scratchObj = newSym(skVar, getIdent"scratch", owner, n.info)
+  var scratchObj = newSym(skVar, getIdent"scratch", owner, n.info, g.config.options)
   block:
     scratchObj.typ = objType
     incl(scratchObj.flags, sfFromGeneric)
@@ -644,36 +648,36 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
   # templates and macros are in fact valid here due to the nature of
   # the transformation:
   if fn.kind == nkClosure:
-    localError(n.info, "closure in spawn environment is not allowed")
+    localError(g.config, n.info, "closure in spawn environment is not allowed")
   if not (fn.kind == nkSym and fn.sym.kind in {skProc, skTemplate, skMacro,
                                                skFunc, skMethod, skConverter}):
     # for indirect calls we pass the function pointer in the scratchObj
     var argType = n[0].typ.skipTypes(abstractInst)
-    var field = newSym(skField, getIdent"fn", owner, n.info)
+    var field = newSym(skField, getIdent"fn", owner, n.info, g.config.options)
     field.typ = argType
     objType.addField(field)
     result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0])
     fn = indirectAccess(castExpr, field, n.info)
   elif fn.kind == nkSym and fn.sym.kind == skIterator:
-    localError(n.info, "iterator in spawn environment is not allowed")
+    localError(g.config, n.info, "iterator in spawn environment is not allowed")
   elif fn.typ.callConv == ccClosure:
-    localError(n.info, "closure in spawn environment is not allowed")
+    localError(g.config, n.info, "closure in spawn environment is not allowed")
 
   call.add(fn)
   var varSection = newNodeI(nkVarSection, n.info)
   var varInit = newNodeI(nkStmtList, n.info)
   if barrier.isNil:
-    setupArgsForConcurrency(n, objType, scratchObj, castExpr, call,
+    setupArgsForConcurrency(g, n, objType, scratchObj, castExpr, call,
                             varSection, varInit, result)
   else:
-    setupArgsForParallelism(n, objType, scratchObj, castExpr, call,
+    setupArgsForParallelism(g, n, objType, scratchObj, castExpr, call,
                             varSection, varInit, result)
 
   var barrierAsExpr: PNode = nil
   if barrier != nil:
     let typ = newType(tyPtr, owner)
-    typ.rawAddSon(magicsys.getCompilerProc("Barrier").typ)
-    var field = newSym(skField, getIdent"barrier", owner, n.info)
+    typ.rawAddSon(magicsys.getCompilerProc(g, "Barrier").typ)
+    var field = newSym(skField, getIdent"barrier", owner, n.info, g.config.options)
     field.typ = typ
     objType.addField(field)
     result.add newFastAsgnStmt(newDotExpr(scratchObj, field), barrier)
@@ -681,7 +685,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
 
   var fvField, fvAsExpr: PNode = nil
   if spawnKind == srFlowVar:
-    var field = newSym(skField, getIdent"fv", owner, n.info)
+    var field = newSym(skField, getIdent"fv", owner, n.info, g.config.options)
     field.typ = retType
     objType.addField(field)
     fvField = newDotExpr(scratchObj, field)
@@ -689,20 +693,20 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
     # create flowVar:
     result.add newFastAsgnStmt(fvField, callProc(spawnExpr[^1]))
     if barrier == nil:
-      result.add callCodegenProc("nimFlowVarCreateSemaphore", fvField)
+      result.add callCodegenProc(g, "nimFlowVarCreateSemaphore", fvField)
 
   elif spawnKind == srByVar:
-    var field = newSym(skField, getIdent"fv", owner, n.info)
+    var field = newSym(skField, getIdent"fv", owner, n.info, g.config.options)
     field.typ = newType(tyPtr, objType.owner)
     field.typ.rawAddSon(retType)
     objType.addField(field)
     fvAsExpr = indirectAccess(castExpr, field, n.info)
     result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest))
 
-  let wrapper = createWrapperProc(fn, threadParam, argsParam,
+  let wrapper = createWrapperProc(g, fn, threadParam, argsParam,
                                   varSection, varInit, call,
                                   barrierAsExpr, fvAsExpr, spawnKind)
-  result.add callCodegenProc("nimSpawn" & $spawnExpr.len, wrapper.newSymNode,
+  result.add callCodegenProc(g, "nimSpawn" & $spawnExpr.len, wrapper.newSymNode,
                              genAddrOf(scratchObj.newSymNode), nil, spawnExpr)
 
   if spawnKind == srFlowVar: result.add fvField
diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim
index 6a9d69082..b5577d961 100644
--- a/compiler/magicsys.nim
+++ b/compiler/magicsys.nim
@@ -10,63 +10,62 @@
 # Built-in types and compilerprocs are registered here.
 
 import
-  ast, astalgo, hashes, msgs, platform, nversion, times, idents, rodread
+  ast, astalgo, hashes, msgs, platform, nversion, times, idents, rodread,
+  modulegraphs
 
-var systemModule*: PSym
+export createMagic
 
-var
-  gSysTypes: array[TTypeKind, PType]
-  compilerprocs: TStrTable
-  exposed: TStrTable
+proc nilOrSysInt*(g: ModuleGraph): PType = g.sysTypes[tyInt]
 
-proc nilOrSysInt*: PType = gSysTypes[tyInt]
+proc registerSysType*(g: ModuleGraph; t: PType) =
+  if g.sysTypes[t.kind] == nil: g.sysTypes[t.kind] = t
 
-proc registerSysType*(t: PType) =
-  if gSysTypes[t.kind] == nil: gSysTypes[t.kind] = t
-
-proc newSysType(kind: TTypeKind, size: int): PType =
-  result = newType(kind, systemModule)
+proc newSysType(g: ModuleGraph; kind: TTypeKind, size: int): PType =
+  result = newType(kind, g.systemModule)
   result.size = size
   result.align = size.int16
 
-proc getSysSym*(name: string): PSym =
-  result = strTableGet(systemModule.tab, getIdent(name))
+proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym =
+  result = strTableGet(g.systemModule.tab, getIdent(name))
   if result == nil:
-    rawMessage(errSystemNeeds, name)
-    result = newSym(skError, getIdent(name), systemModule, systemModule.info)
-    result.typ = newType(tyError, systemModule)
+    localError(g.config, info, "system module needs: " & name)
+    result = newSym(skError, getIdent(name), g.systemModule, g.systemModule.info, {})
+    result.typ = newType(tyError, g.systemModule)
   if result.kind == skStub: loadStub(result)
   if result.kind == skAlias: result = result.owner
 
-proc createMagic*(name: string, m: TMagic): PSym =
-  result = newSym(skProc, getIdent(name), nil, unknownLineInfo())
-  result.magic = m
+when false:
+  proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym =
+    result = newSym(skProc, getIdent(name), nil, unknownLineInfo())
+    result.magic = m
 
-let
-  opNot* = createMagic("not", mNot)
-  opContains* = createMagic("contains", mInSet)
+when false:
+  let
+    opNot* = createMagic("not", mNot)
+    opContains* = createMagic("contains", mInSet)
 
-proc getSysMagic*(name: string, m: TMagic): PSym =
+proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym =
   var ti: TIdentIter
   let id = getIdent(name)
-  var r = initIdentIter(ti, systemModule.tab, id)
+  var r = initIdentIter(ti, g.systemModule.tab, id)
   while r != nil:
     if r.kind == skStub: loadStub(r)
     if r.magic == m:
       # prefer the tyInt variant:
       if r.typ.sons[0] != nil and r.typ.sons[0].kind == tyInt: return r
       result = r
-    r = nextIdentIter(ti, systemModule.tab)
+    r = nextIdentIter(ti, g.systemModule.tab)
   if result != nil: return result
-  rawMessage(errSystemNeeds, name)
-  result = newSym(skError, id, systemModule, systemModule.info)
-  result.typ = newType(tyError, systemModule)
+  localError(g.config, info, "system module needs: " & name)
+  result = newSym(skError, id, g.systemModule, g.systemModule.info, {})
+  result.typ = newType(tyError, g.systemModule)
 
-proc sysTypeFromName*(name: string): PType =
-  result = getSysSym(name).typ
+proc sysTypeFromName*(g: ModuleGraph; info: TLineInfo; name: string): PType =
+  result = getSysSym(g, info, name).typ
 
-proc getSysType*(kind: TTypeKind): PType =
-  result = gSysTypes[kind]
+proc getSysType*(g: ModuleGraph; info: TLineInfo; kind: TTypeKind): PType =
+  template sysTypeFromName(s: string): untyped = sysTypeFromName(g, info, s)
+  result = g.sysTypes[kind]
   if result == nil:
     case kind
     of tyInt: result = sysTypeFromName("int")
@@ -88,51 +87,49 @@ proc getSysType*(kind: TTypeKind): PType =
     of tyString: result = sysTypeFromName("string")
     of tyCString: result = sysTypeFromName("cstring")
     of tyPointer: result = sysTypeFromName("pointer")
-    of tyNil: result = newSysType(tyNil, ptrSize)
-    else: internalError("request for typekind: " & $kind)
-    gSysTypes[kind] = result
+    of tyNil: result = newSysType(g, tyNil, ptrSize)
+    else: internalError(g.config, "request for typekind: " & $kind)
+    g.sysTypes[kind] = result
   if result.kind != kind:
-    internalError("wanted: " & $kind & " got: " & $result.kind)
-  if result == nil: internalError("type not found: " & $kind)
-
-var
-  intTypeCache: array[-5..64, PType]
+    internalError(g.config, "wanted: " & $kind & " got: " & $result.kind)
+  if result == nil: internalError(g.config, "type not found: " & $kind)
 
-proc resetSysTypes* =
-  systemModule = nil
-  initStrTable(compilerprocs)
-  initStrTable(exposed)
-  for i in low(gSysTypes)..high(gSysTypes):
-    gSysTypes[i] = nil
+proc resetSysTypes*(g: ModuleGraph) =
+  g.systemModule = nil
+  initStrTable(g.compilerprocs)
+  initStrTable(g.exposed)
+  for i in low(g.sysTypes)..high(g.sysTypes):
+    g.sysTypes[i] = nil
 
-  for i in low(intTypeCache)..high(intTypeCache):
-    intTypeCache[i] = nil
+  for i in low(g.intTypeCache)..high(g.intTypeCache):
+    g.intTypeCache[i] = nil
 
-proc getIntLitType*(literal: PNode): PType =
+proc getIntLitType*(g: ModuleGraph; literal: PNode): PType =
   # we cache some common integer literal types for performance:
   let value = literal.intVal
-  if value >= low(intTypeCache) and value <= high(intTypeCache):
-    result = intTypeCache[value.int]
+  if value >= low(g.intTypeCache) and value <= high(g.intTypeCache):
+    result = g.intTypeCache[value.int]
     if result == nil:
-      let ti = getSysType(tyInt)
+      let ti = getSysType(g, literal.info, tyInt)
       result = copyType(ti, ti.owner, false)
       result.n = literal
-      intTypeCache[value.int] = result
+      g.intTypeCache[value.int] = result
   else:
-    let ti = getSysType(tyInt)
+    let ti = getSysType(g, literal.info, tyInt)
     result = copyType(ti, ti.owner, false)
     result.n = literal
 
-proc getFloatLitType*(literal: PNode): PType =
+proc getFloatLitType*(g: ModuleGraph; literal: PNode): PType =
   # for now we do not cache these:
-  result = newSysType(tyFloat, size=8)
+  result = newSysType(g, tyFloat, size=8)
   result.n = literal
 
 proc skipIntLit*(t: PType): PType {.inline.} =
-  if t.n != nil:
-    if t.kind in {tyInt, tyFloat}:
-      return getSysType(t.kind)
-  result = t
+  if t.n != nil and t.kind in {tyInt, tyFloat}:
+    result = copyType(t, t.owner, false)
+    result.n = nil
+  else:
+    result = t
 
 proc addSonSkipIntLit*(father, son: PType) =
   if isNil(father.sons): father.sons = @[]
@@ -140,60 +137,59 @@ proc addSonSkipIntLit*(father, son: PType) =
   add(father.sons, s)
   propagateToOwner(father, s)
 
-proc setIntLitType*(result: PNode) =
+proc setIntLitType*(g: ModuleGraph; result: PNode) =
   let i = result.intVal
   case platform.intSize
-  of 8: result.typ = getIntLitType(result)
+  of 8: result.typ = getIntLitType(g, result)
   of 4:
     if i >= low(int32) and i <= high(int32):
-      result.typ = getIntLitType(result)
+      result.typ = getIntLitType(g, result)
     else:
-      result.typ = getSysType(tyInt64)
+      result.typ = getSysType(g, result.info, tyInt64)
   of 2:
     if i >= low(int16) and i <= high(int16):
-      result.typ = getIntLitType(result)
+      result.typ = getIntLitType(g, result)
     elif i >= low(int32) and i <= high(int32):
-      result.typ = getSysType(tyInt32)
+      result.typ = getSysType(g, result.info, tyInt32)
     else:
-      result.typ = getSysType(tyInt64)
+      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(result)
+      result.typ = getIntLitType(g, result)
     elif i >= low(int16) and i <= high(int16):
-      result.typ = getSysType(tyInt16)
+      result.typ = getSysType(g, result.info, tyInt16)
     elif i >= low(int32) and i <= high(int32):
-      result.typ = getSysType(tyInt32)
+      result.typ = getSysType(g, result.info, tyInt32)
     else:
-      result.typ = getSysType(tyInt64)
-  else: internalError(result.info, "invalid int size")
+      result.typ = getSysType(g, result.info, tyInt64)
+  else:
+    internalError(g.config, result.info, "invalid int size")
 
-proc getCompilerProc*(name: string): PSym =
+proc getCompilerProc*(g: ModuleGraph; name: string): PSym =
   let ident = getIdent(name)
-  result = strTableGet(compilerprocs, ident)
-  if result == nil:
-    result = strTableGet(rodCompilerprocs, ident)
-    if result != nil:
-      strTableAdd(compilerprocs, result)
-      if result.kind == skStub: loadStub(result)
-      if result.kind == skAlias: result = result.owner
+  result = strTableGet(g.compilerprocs, ident)
+  when false:
+    if result == nil:
+      result = strTableGet(g.rodCompilerprocs, ident)
+      if result != nil:
+        strTableAdd(g.compilerprocs, result)
+        if result.kind == skStub: loadStub(result)
+        if result.kind == skAlias: result = result.owner
 
-proc registerCompilerProc*(s: PSym) =
-  strTableAdd(compilerprocs, s)
+proc registerCompilerProc*(g: ModuleGraph; s: PSym) =
+  strTableAdd(g.compilerprocs, s)
 
-proc registerNimScriptSymbol*(s: PSym) =
+proc registerNimScriptSymbol*(g: ModuleGraph; s: PSym) =
   # Nimscript symbols must be al unique:
-  let conflict = strTableGet(exposed, s.name)
+  let conflict = strTableGet(g.exposed, s.name)
   if conflict == nil:
-    strTableAdd(exposed, s)
+    strTableAdd(g.exposed, s)
   else:
-    localError(s.info, "symbol conflicts with other .exportNims symbol at: " &
-      $conflict.info)
-
-proc getNimScriptSymbol*(name: string): PSym =
-  strTableGet(exposed, getIdent(name))
+    localError(g.config, s.info,
+      "symbol conflicts with other .exportNims symbol at: " & $conflict.info)
 
-proc resetNimScriptSymbols*() = initStrTable(exposed)
+proc getNimScriptSymbol*(g: ModuleGraph; name: string): PSym =
+  strTableGet(g.exposed, getIdent(name))
 
-initStrTable(compilerprocs)
-initStrTable(exposed)
+proc resetNimScriptSymbols*(g: ModuleGraph) = initStrTable(g.exposed)
diff --git a/compiler/main.nim b/compiler/main.nim
index f23a3a88e..e3f00db9e 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -16,12 +16,12 @@ import
   cgen, jsgen, json, nversion,
   platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
   docgen2, service, parser, modules, ccgutils, sigmatch, ropes,
-  modulegraphs, tables, rod
+  modulegraphs, tables, rod, configuration
 
-from magicsys import systemModule, resetSysTypes
+from magicsys import resetSysTypes
 
-proc rodPass =
-  if gSymbolFiles in {enabledSf, writeOnlySf}:
+proc rodPass(g: ModuleGraph) =
+  if g.config.symbolFiles in {enabledSf, writeOnlySf}:
     registerPass(rodwritePass)
 
 proc codegenPass =
@@ -46,54 +46,55 @@ proc commandGenDepend(graph: ModuleGraph; cache: IdentCache) =
   registerPass(gendependPass)
   #registerPass(cleanupPass)
   compileProject(graph, cache)
-  writeDepsFile(graph, gProjectFull)
-  generateDot(gProjectFull)
-  execExternalProgram("dot -Tpng -o" & changeFileExt(gProjectFull, "png") &
-      ' ' & changeFileExt(gProjectFull, "dot"))
+  let project = graph.config.projectFull
+  writeDepsFile(graph, project)
+  generateDot(project)
+  execExternalProgram(graph.config, "dot -Tpng -o" & changeFileExt(project, "png") &
+      ' ' & changeFileExt(project, "dot"))
 
 proc commandCheck(graph: ModuleGraph; cache: IdentCache) =
-  msgs.gErrorMax = high(int)  # do not stop after first error
-  defineSymbol("nimcheck")
+  graph.config.errorMax = high(int)  # do not stop after first error
+  defineSymbol(graph.config.symbols, "nimcheck")
   semanticPasses()            # use an empty backend for semantic checking only
-  rodPass()
+  rodPass(graph)
   compileProject(graph, cache)
 
 proc commandDoc2(graph: ModuleGraph; cache: IdentCache; json: bool) =
-  msgs.gErrorMax = high(int)  # do not stop after first error
+  graph.config.errorMax = high(int)  # do not stop after first error
   semanticPasses()
   if json: registerPass(docgen2JsonPass)
   else: registerPass(docgen2Pass)
   #registerPass(cleanupPass())
   compileProject(graph, cache)
-  finishDoc2Pass(gProjectName)
+  finishDoc2Pass(graph.config.projectName)
 
 proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) =
-  extccomp.initVars()
+  let conf = graph.config
+  extccomp.initVars(conf)
   semanticPasses()
   registerPass(cgenPass)
-  rodPass()
+  rodPass(graph)
   #registerPass(cleanupPass())
 
   compileProject(graph, cache)
-  cgenWriteModules(graph.backend, graph.config)
-  if gCmd != cmdRun:
-    let proj = changeFileExt(gProjectFull, "")
-    extccomp.callCCompiler(proj)
-    extccomp.writeJsonBuildInstructions(proj)
-    if optGenScript in gGlobalOptions:
-      writeDepsFile(graph, toGeneratedFile(proj, ""))
+  cgenWriteModules(graph.backend, conf)
+  if conf.cmd != cmdRun:
+    let proj = changeFileExt(conf.projectFull, "")
+    extccomp.callCCompiler(conf, proj)
+    extccomp.writeJsonBuildInstructions(conf, proj)
+    if optGenScript in graph.config.globalOptions:
+      writeDepsFile(graph, toGeneratedFile(conf, proj, ""))
 
 proc commandJsonScript(graph: ModuleGraph; cache: IdentCache) =
-  let proj = changeFileExt(gProjectFull, "")
-  extccomp.runJsonBuildInstructions(proj)
+  let proj = changeFileExt(graph.config.projectFull, "")
+  extccomp.runJsonBuildInstructions(graph.config, proj)
 
 proc commandCompileToJS(graph: ModuleGraph; cache: IdentCache) =
   #incl(gGlobalOptions, optSafeCode)
   setTarget(osJS, cpuJS)
   #initDefines()
-  defineSymbol("nimrod") # 'nimrod' is always defined
-  defineSymbol("ecmascript") # For backward compatibility
-  defineSymbol("js")
+  defineSymbol(graph.config.symbols, "ecmascript") # For backward compatibility
+  defineSymbol(graph.config.symbols, "js")
   semanticPasses()
   registerPass(JSgenPass)
   compileProject(graph, cache)
@@ -101,19 +102,19 @@ proc commandCompileToJS(graph: ModuleGraph; cache: IdentCache) =
 proc interactivePasses(graph: ModuleGraph; cache: IdentCache) =
   #incl(gGlobalOptions, optSafeCode)
   #setTarget(osNimrodVM, cpuNimrodVM)
-  initDefines()
-  defineSymbol("nimscript")
-  when hasFFI: defineSymbol("nimffi")
+  initDefines(graph.config.symbols)
+  defineSymbol(graph.config.symbols, "nimscript")
+  when hasFFI: defineSymbol(graph.config.symbols, "nimffi")
   registerPass(verbosePass)
   registerPass(semPass)
   registerPass(evalPass)
 
 proc commandInteractive(graph: ModuleGraph; cache: IdentCache) =
-  msgs.gErrorMax = high(int)  # do not stop after first error
+  graph.config.errorMax = high(int)  # do not stop after first error
   interactivePasses(graph, cache)
   compileSystemModule(graph, cache)
-  if commandArgs.len > 0:
-    discard graph.compileModule(fileInfoIdx(gProjectFull), cache, {})
+  if graph.config.commandArgs.len > 0:
+    discard graph.compileModule(fileInfoIdx(graph.config, graph.config.projectFull), cache, {})
   else:
     var m = graph.makeStdinModule()
     incl(m.flags, sfMainModule)
@@ -125,7 +126,7 @@ proc evalNim(graph: ModuleGraph; nodes: PNode, module: PSym; cache: IdentCache)
   carryPasses(graph, nodes, module, cache, evalPasses)
 
 proc commandEval(graph: ModuleGraph; cache: IdentCache; exp: string) =
-  if systemModule == nil:
+  if graph.systemModule == nil:
     interactivePasses(graph, cache)
     compileSystemModule(graph, cache)
   let echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
@@ -133,7 +134,7 @@ proc commandEval(graph: ModuleGraph; cache: IdentCache; exp: string) =
     makeStdinModule(graph), cache)
 
 proc commandScan(cache: IdentCache, config: ConfigRef) =
-  var f = addFileExt(mainCommandArg(), NimExt)
+  var f = addFileExt(mainCommandArg(config), NimExt)
   var stream = llStreamOpen(f, fmRead)
   if stream != nil:
     var
@@ -143,159 +144,153 @@ proc commandScan(cache: IdentCache, config: ConfigRef) =
     openLexer(L, f, stream, cache, config)
     while true:
       rawGetTok(L, tok)
-      printTok(tok)
+      printTok(config, tok)
       if tok.tokType == tkEof: break
     closeLexer(L)
   else:
-    rawMessage(errCannotOpenFile, f)
+    rawMessage(config, errGenerated, "cannot open file: " & f)
 
 const
-  SimulateCaasMemReset = false
   PrintRopeCacheStats = false
 
 proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
-  when SimulateCaasMemReset:
-    gGlobalOptions.incl(optCaasEnabled)
+  let conf = graph.config
 
   setupModuleCache()
   # In "nim serve" scenario, each command must reset the registered passes
   clearPasses()
-  gLastCmdTime = epochTime()
-  searchPaths.add(options.libpath)
-  when false: # gProjectFull.len != 0:
-    # current path is always looked first for modules
-    prependStr(searchPaths, gProjectPath)
+  conf.lastCmdTime = epochTime()
+  conf.searchPaths.add(conf.libpath)
   setId(100)
-  case command.normalize
+  case conf.command.normalize
   of "c", "cc", "compile", "compiletoc":
     # compile means compileToC currently
-    gCmd = cmdCompileToC
+    conf.cmd = cmdCompileToC
     commandCompileToC(graph, cache)
   of "cpp", "compiletocpp":
-    gCmd = cmdCompileToCpp
-    defineSymbol("cpp")
+    conf.cmd = cmdCompileToCpp
+    defineSymbol(graph.config.symbols, "cpp")
     commandCompileToC(graph, cache)
   of "objc", "compiletooc":
-    gCmd = cmdCompileToOC
-    defineSymbol("objc")
+    conf.cmd = cmdCompileToOC
+    defineSymbol(graph.config.symbols, "objc")
     commandCompileToC(graph, cache)
   of "run":
-    gCmd = cmdRun
+    conf.cmd = cmdRun
     when hasTinyCBackend:
       extccomp.setCC("tcc")
       commandCompileToC(graph, cache)
     else:
-      rawMessage(errInvalidCommandX, command)
+      rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc")
   of "js", "compiletojs":
-    gCmd = cmdCompileToJS
+    conf.cmd = cmdCompileToJS
     commandCompileToJS(graph, cache)
   of "doc0":
-    wantMainModule()
-    gCmd = cmdDoc
-    loadConfigs(DocConfig, cache)
-    commandDoc()
+    wantMainModule(conf)
+    conf.cmd = cmdDoc
+    loadConfigs(DocConfig, cache, conf)
+    commandDoc(conf)
   of "doc2", "doc":
-    gCmd = cmdDoc
-    loadConfigs(DocConfig, cache)
-    defineSymbol("nimdoc")
+    conf.cmd = cmdDoc
+    loadConfigs(DocConfig, cache, conf)
+    defineSymbol(conf.symbols, "nimdoc")
     commandDoc2(graph, cache, false)
   of "rst2html":
-    gCmd = cmdRst2html
-    loadConfigs(DocConfig, cache)
-    commandRst2Html()
+    conf.cmd = cmdRst2html
+    loadConfigs(DocConfig, cache, conf)
+    commandRst2Html(conf)
   of "rst2tex":
-    gCmd = cmdRst2tex
-    loadConfigs(DocTexConfig, cache)
-    commandRst2TeX()
+    conf.cmd = cmdRst2tex
+    loadConfigs(DocTexConfig, cache, conf)
+    commandRst2TeX(conf)
   of "jsondoc0":
-    wantMainModule()
-    gCmd = cmdDoc
-    loadConfigs(DocConfig, cache)
-    wantMainModule()
-    defineSymbol("nimdoc")
-    commandJson()
+    wantMainModule(conf)
+    conf.cmd = cmdDoc
+    loadConfigs(DocConfig, cache, conf)
+    wantMainModule(conf)
+    defineSymbol(conf.symbols, "nimdoc")
+    commandJson(conf)
   of "jsondoc2", "jsondoc":
-    gCmd = cmdDoc
-    loadConfigs(DocConfig, cache)
-    wantMainModule()
-    defineSymbol("nimdoc")
+    conf.cmd = cmdDoc
+    loadConfigs(DocConfig, cache, conf)
+    wantMainModule(conf)
+    defineSymbol(conf.symbols, "nimdoc")
     commandDoc2(graph, cache, true)
   of "ctags":
-    wantMainModule()
-    gCmd = cmdDoc
-    loadConfigs(DocConfig, cache)
-    wantMainModule()
-    defineSymbol("nimdoc")
-    commandTags()
+    wantMainModule(conf)
+    conf.cmd = cmdDoc
+    loadConfigs(DocConfig, cache, conf)
+    defineSymbol(conf.symbols, "nimdoc")
+    commandTags(conf)
   of "buildindex":
-    gCmd = cmdDoc
-    loadConfigs(DocConfig, cache)
-    commandBuildIndex()
+    conf.cmd = cmdDoc
+    loadConfigs(DocConfig, cache, conf)
+    commandBuildIndex(conf)
   of "gendepend":
-    gCmd = cmdGenDepend
+    conf.cmd = cmdGenDepend
     commandGenDepend(graph, cache)
   of "dump":
-    gCmd = cmdDump
-    if getConfigVar("dump.format") == "json":
-      wantMainModule()
+    conf.cmd = cmdDump
+    if getConfigVar(conf, "dump.format") == "json":
+      wantMainModule(conf)
 
       var definedSymbols = newJArray()
-      for s in definedSymbolNames(): definedSymbols.elems.add(%s)
+      for s in definedSymbolNames(conf.symbols): definedSymbols.elems.add(%s)
 
       var libpaths = newJArray()
-      for dir in searchPaths: libpaths.elems.add(%dir)
+      for dir in conf.searchPaths: libpaths.elems.add(%dir)
 
       var dumpdata = % [
         (key: "version", val: %VersionAsString),
-        (key: "project_path", val: %gProjectFull),
+        (key: "project_path", val: %conf.projectFull),
         (key: "defined_symbols", val: definedSymbols),
         (key: "lib_paths", val: libpaths)
       ]
 
-      msgWriteln($dumpdata, {msgStdout, msgSkipHook})
+      msgWriteln(conf, $dumpdata, {msgStdout, msgSkipHook})
     else:
-      msgWriteln("-- list of currently defined symbols --",
+      msgWriteln(conf, "-- list of currently defined symbols --",
                  {msgStdout, msgSkipHook})
-      for s in definedSymbolNames(): msgWriteln(s, {msgStdout, msgSkipHook})
-      msgWriteln("-- end of list --", {msgStdout, msgSkipHook})
+      for s in definedSymbolNames(conf.symbols): msgWriteln(conf, s, {msgStdout, msgSkipHook})
+      msgWriteln(conf, "-- end of list --", {msgStdout, msgSkipHook})
 
-      for it in searchPaths: msgWriteln(it)
+      for it in conf.searchPaths: msgWriteln(conf, it)
   of "check":
-    gCmd = cmdCheck
+    conf.cmd = cmdCheck
     commandCheck(graph, cache)
   of "parse":
-    gCmd = cmdParse
-    wantMainModule()
-    discard parseFile(FileIndex gProjectMainIdx, cache, graph.config)
+    conf.cmd = cmdParse
+    wantMainModule(conf)
+    discard parseFile(FileIndex conf.projectMainIdx, cache, conf)
   of "scan":
-    gCmd = cmdScan
-    wantMainModule()
-    commandScan(cache, graph.config)
-    msgWriteln("Beware: Indentation tokens depend on the parser's state!")
+    conf.cmd = cmdScan
+    wantMainModule(conf)
+    commandScan(cache, conf)
+    msgWriteln(conf, "Beware: Indentation tokens depend on the parser's state!")
   of "secret":
-    gCmd = cmdInteractive
+    conf.cmd = cmdInteractive
     commandInteractive(graph, cache)
   of "e":
-    commandEval(graph, cache, mainCommandArg())
+    commandEval(graph, cache, mainCommandArg(conf))
   of "nop", "help":
     # prevent the "success" message:
-    gCmd = cmdDump
+    conf.cmd = cmdDump
   of "jsonscript":
-    gCmd = cmdJsonScript
+    conf.cmd = cmdJsonScript
     commandJsonScript(graph, cache)
   else:
-    rawMessage(errInvalidCommandX, command)
+    rawMessage(conf, errGenerated, "invalid command: " & conf.command)
 
-  if msgs.gErrorCounter == 0 and
-     gCmd notin {cmdInterpret, cmdRun, cmdDump}:
+  if conf.errorCounter == 0 and
+     conf.cmd notin {cmdInterpret, cmdRun, cmdDump}:
     when declared(system.getMaxMem):
       let usedMem = formatSize(getMaxMem()) & " peakmem"
     else:
       let usedMem = formatSize(getTotalMem())
-    rawMessage(hintSuccessX, [$graph.config.linesCompiled,
-               formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3),
+    rawMessage(conf, hintSuccessX, [$conf.linesCompiled,
+               formatFloat(epochTime() - conf.lastCmdTime, ffDecimal, 3),
                usedMem,
-               if condSyms.isDefined("release"): "Release Build"
+               if isDefined(conf, "release"): "Release Build"
                else: "Debug Build"])
 
   when PrintRopeCacheStats:
@@ -306,9 +301,6 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
     echo "  efficiency: ", formatFloat(1-(gCacheMisses.float/gCacheTries.float),
                                        ffDecimal, 3)
 
-  when SimulateCaasMemReset:
-    resetMemory()
+  resetAttributes(conf)
 
-  resetAttributes()
-
-proc mainCommand*() = mainCommand(newModuleGraph(newConfigRef()), newIdentCache())
+#proc mainCommand*() = mainCommand(newModuleGraph(newConfigRef()), newIdentCache())
diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim
index 6c14a46e8..460d0b4a5 100644
--- a/compiler/modulegraphs.nim
+++ b/compiler/modulegraphs.nim
@@ -25,7 +25,7 @@
 ## - Its dependent module stays the same.
 ##
 
-import ast, intsets, tables, options, rod, msgs, hashes
+import ast, intsets, tables, options, rod, msgs, hashes, idents
 
 type
   ModuleGraph* = ref object
@@ -44,6 +44,12 @@ type
     usageSym*: PSym # for nimsuggest
     owners*: seq[PSym]
     methods*: seq[tuple[methods: TSymSeq, dispatcher: PSym]]
+    systemModule*: PSym
+    sysTypes*: array[TTypeKind, PType]
+    compilerprocs*: TStrTable
+    exposed*: TStrTable
+    intTypeCache*: array[-5..64, PType]
+    opContains*, opNot*: PSym
 
 proc hash*(x: FileIndex): Hash {.borrow.}
 
@@ -52,6 +58,10 @@ proc hash*(x: FileIndex): Hash {.borrow.}
 proc stopCompile*(g: ModuleGraph): bool {.inline.} =
   result = doStopCompile != nil and doStopCompile()
 
+proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym =
+  result = newSym(skProc, getIdent(name), nil, unknownLineInfo(), {})
+  result.magic = m
+
 proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph =
   result = ModuleGraph()
   initStrTable(result.packageSyms)
@@ -65,6 +75,10 @@ proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph =
     result.config = config
   result.owners = @[]
   result.methods = @[]
+  initStrTable(result.compilerprocs)
+  initStrTable(result.exposed)
+  result.opNot = createMagic(result, "not", mNot)
+  result.opContains = createMagic(result, "contains", mInSet)
 
 proc resetAllModules*(g: ModuleGraph) =
   initStrTable(packageSyms)
@@ -75,6 +89,8 @@ proc resetAllModules*(g: ModuleGraph) =
   usageSym = nil
   owners = @[]
   methods = @[]
+  initStrTable(compilerprocs)
+  initStrTable(exposed)
 
 proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
   if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len:
diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim
index 1318b67a7..daa55c2ba 100644
--- a/compiler/modulepaths.nim
+++ b/compiler/modulepaths.nim
@@ -113,16 +113,16 @@ when false:
       localError(pkg.info, "package name must be an identifier or string literal")
       result = ""
 
-proc getModuleName*(n: PNode): string =
+proc getModuleName*(conf: ConfigRef; n: PNode): string =
   # This returns a short relative module name without the nim extension
   # e.g. like "system", "importer" or "somepath/module"
   # The proc won't perform any checks that the path is actually valid
   case n.kind
   of nkStrLit, nkRStrLit, nkTripleStrLit:
     try:
-      result = pathSubs(n.strVal, n.info.toFullPath().splitFile().dir)
+      result = pathSubs(conf, n.strVal, n.info.toFullPath().splitFile().dir)
     except ValueError:
-      localError(n.info, "invalid path: " & n.strVal)
+      localError(conf, n.info, "invalid path: " & n.strVal)
       result = n.strVal
   of nkIdent:
     result = n.ident.s
@@ -137,7 +137,7 @@ proc getModuleName*(n: PNode): string =
       n.sons[0] = n.sons[1]
       n.sons[1] = n.sons[2]
       n.sons.setLen(2)
-      return getModuleName(n.sons[0])
+      return getModuleName(conf, n.sons[0])
     when false:
       if n1.kind == nkPrefix and n1[0].kind == nkIdent and n1[0].ident.s == "$":
         if n0.kind == nkIdent and n0.ident.s == "/":
@@ -146,16 +146,16 @@ proc getModuleName*(n: PNode): string =
           localError(n.info, "only '/' supported with $package notation")
           result = ""
     else:
-      let modname = getModuleName(n[2])
+      let modname = getModuleName(conf, n[2])
       if $n1 == "std":
         template attempt(a) =
           let x = addFileExt(a, "nim")
           if fileExists(x): return x
         for candidate in stdlibDirs:
-          attempt(options.libpath / candidate / modname)
+          attempt(conf.libpath / candidate / modname)
 
       # hacky way to implement 'x / y /../ z':
-      result = getModuleName(n1)
+      result = getModuleName(conf, n1)
       result.add renderTree(n0, {renderNoComments})
       result.add modname
   of nkPrefix:
@@ -169,19 +169,19 @@ proc getModuleName*(n: PNode): string =
   of nkDotExpr:
     result = renderTree(n, {renderNoComments}).replace(".", "/")
   of nkImportAs:
-    result = getModuleName(n.sons[0])
+    result = getModuleName(conf, n.sons[0])
   else:
-    localError(n.info, errGenerated, "invalid module name: '$1'" % n.renderTree)
+    localError(conf, n.info, "invalid module name: '$1'" % n.renderTree)
     result = ""
 
-proc checkModuleName*(n: PNode; doLocalError=true): FileIndex =
+proc checkModuleName*(conf: ConfigRef; n: PNode; doLocalError=true): FileIndex =
   # This returns the full canonical path for a given module import
-  let modulename = n.getModuleName
-  let fullPath = findModule(modulename, n.info.toFullPath)
+  let modulename = getModuleName(conf, n)
+  let fullPath = findModule(conf, modulename, n.info.toFullPath)
   if fullPath.len == 0:
     if doLocalError:
       let m = if modulename.len > 0: modulename else: $n
-      localError(n.info, errCannotOpenFile, m)
+      localError(conf, n.info, "cannot open file: " & m)
     result = InvalidFileIDX
   else:
-    result = fullPath.fileInfoIdx
+    result = fileInfoIdx(conf, fullPath)
diff --git a/compiler/modules.nim b/compiler/modules.nim
index 7fe2336dd..5d1eba1f2 100644
--- a/compiler/modules.nim
+++ b/compiler/modules.nim
@@ -11,10 +11,11 @@
 
 import
   ast, astalgo, magicsys, std / sha1, rodread, msgs, cgendata, sigmatch, options,
-  idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs, rod
+  idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs, rod,
+  configuration
 
-proc resetSystemArtifacts*() =
-  magicsys.resetSysTypes()
+proc resetSystemArtifacts*(g: ModuleGraph) =
+  magicsys.resetSysTypes(g)
 
 proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
   # We cannot call ``newSym`` here, because we have to circumvent the ID
@@ -25,11 +26,11 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
   let filename = fileIdx.toFullPath
   result.name = getIdent(splitFile(filename).name)
   if not isNimIdentifier(result.name.s):
-    rawMessage(errInvalidModuleName, result.name.s)
+    rawMessage(graph.config, errGenerated, "invalid module name: " & result.name.s)
 
   result.info = newLineInfo(fileIdx, 1, 1)
   let
-    pck = getPackageName(filename)
+    pck = getPackageName(graph.config, filename)
     pck2 = if pck.len > 0: pck else: "unknown"
     pack = getIdent(pck2)
   var packSym = graph.packageSyms.strTableGet(pack)
@@ -49,7 +50,7 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
   strTableAdd(result.tab, result) # a module knows itself
   let existing = strTableGet(packSym.tab, result.name)
   if existing != nil and existing.info.fileIndex != result.info.fileIndex:
-    localError(result.info, "module names need to be unique per Nimble package; module clashes with " & existing.info.fileIndex.toFullPath)
+    localError(graph.config, result.info, "module names need to be unique per Nimble package; module clashes with " & existing.info.fileIndex.toFullPath)
   # strTableIncl() for error corrections:
   discard strTableIncl(packSym.tab, result)
 
@@ -65,7 +66,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; cache: IdentCache, f
       gMainPackageId = result.owner.id
 
     when false:
-      if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
+      if conf.cmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
         rd = handleSymbolFile(result, cache)
         if result.id < 0:
           internalError("handleSymbolFile should have set the module's ID")
@@ -74,7 +75,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; cache: IdentCache, f
         discard
     result.id = getModuleId(fileIdx, toFullPath(fileIdx))
     discard processModule(graph, result,
-      if sfMainModule in flags and gProjectIsStdin: stdin.llStreamOpen else: nil,
+      if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil,
       rd, cache)
     #if optCaasEnabled in gGlobalOptions:
     #  gMemCacheData[fileIdx].needsRecompile = Recompiled
@@ -85,7 +86,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; cache: IdentCache, f
     initStrTable(result.tab)
     result.ast = nil
     discard processModule(graph, result,
-      if sfMainModule in flags and gProjectIsStdin: stdin.llStreamOpen else: nil,
+      if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil,
       nil, cache)
     graph.markClientsDirty(fileIdx)
     when false:
@@ -97,13 +98,15 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; cache: IdentCache, f
 proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
                    cache: IdentCache): PSym {.procvar.} =
   # this is called by the semantic checking phase
+  assert graph.config != nil
   result = compileModule(graph, fileIdx, cache, {})
   graph.addDep(s, fileIdx)
   #if sfSystemModule in result.flags:
   #  localError(result.info, errAttemptToRedefine, result.name.s)
   # restore the notes for outer module:
-  gNotes = if s.owner.id == gMainPackageId: gMainPackageNotes
-           else: ForeignPackageNotes
+  graph.config.notes =
+      if s.owner.id == gMainPackageId: graph.config.mainPackageNotes
+      else: graph.config.foreignPackageNotes
 
 proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
                     cache: IdentCache): PNode {.procvar.} =
@@ -112,23 +115,24 @@ proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
   graph.addIncludeDep(s.position.FileIndex, fileIdx)
 
 proc compileSystemModule*(graph: ModuleGraph; cache: IdentCache) =
-  if magicsys.systemModule == nil:
-    systemFileIdx = fileInfoIdx(options.libpath/"system.nim")
+  if graph.systemModule == nil:
+    systemFileIdx = fileInfoIdx(graph.config, graph.config.libpath / "system.nim")
     discard graph.compileModule(systemFileIdx, cache, {sfSystemModule})
 
-proc wantMainModule* =
-  if gProjectFull.len == 0:
-    fatal(gCmdLineInfo, errCommandExpectsFilename)
-  gProjectMainIdx = int32 addFileExt(gProjectFull, NimExt).fileInfoIdx
+proc wantMainModule*(conf: ConfigRef) =
+  if conf.projectFull.len == 0:
+    fatal(conf, newLineInfo(conf, "command line", 1, 1), errGenerated, "command expects a filename")
+  conf.projectMainIdx = int32 fileInfoIdx(conf, addFileExt(conf.projectFull, NimExt))
 
 passes.gIncludeFile = includeModule
 passes.gImportModule = importModule
 
 proc compileProject*(graph: ModuleGraph; cache: IdentCache;
                      projectFileIdx = InvalidFileIDX) =
-  wantMainModule()
-  let systemFileIdx = fileInfoIdx(options.libpath / "system.nim")
-  let projectFile = if projectFileIdx == InvalidFileIDX: FileIndex(gProjectMainIdx) else: projectFileIdx
+  let conf = graph.config
+  wantMainModule(conf)
+  let systemFileIdx = fileInfoIdx(conf, conf.libpath / "system.nim")
+  let projectFile = if projectFileIdx == InvalidFileIDX: FileIndex(conf.projectMainIdx) else: projectFileIdx
   graph.importStack.add projectFile
   if projectFile == systemFileIdx:
     discard graph.compileModule(projectFile, cache, {sfMainModule, sfSystemModule})
@@ -137,7 +141,7 @@ proc compileProject*(graph: ModuleGraph; cache: IdentCache;
     discard graph.compileModule(projectFile, cache, {sfMainModule})
 
 proc makeModule*(graph: ModuleGraph; filename: string): PSym =
-  result = graph.newModule(fileInfoIdx filename)
+  result = graph.newModule(fileInfoIdx(graph.config, filename))
   result.id = getID()
 
 proc makeStdinModule*(graph: ModuleGraph): PSym = graph.makeModule"stdin"
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index b6cd05e06..533d3a57f 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -8,481 +8,13 @@
 #
 
 import
-  options, strutils, os, tables, ropes, platform, terminal, macros
+  options, strutils, os, tables, ropes, platform, terminal, macros,
+  configuration
 
-const
-  explanationsBaseUrl* = "https://nim-lang.org/docs/manual"
-
-type
-  TMsgKind* = enum
-    errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile, errGenerated,
-    errStringLiteralExpected,
-    errIntLiteralExpected, errInvalidCharacterConstant,
-    errClosingTripleQuoteExpected, errClosingQuoteExpected,
-    errTabulatorsAreNotAllowed, errInvalidToken,
-    errInvalidNumber, errInvalidNumberOctalCode, errNumberOutOfRange,
-    errNnotAllowedInCharacter, errClosingBracketExpected, errMissingFinalQuote,
-    errIdentifierExpected, errNewlineExpected, errInvalidModuleName,
-    errOperatorExpected, errTokenExpected,
-    errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected,
-    errInvalidPragma, errUnknownPragma, errInvalidDirectiveX,
-    errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation,
-    errExceptionAlreadyHandled,
-    errYieldNotAllowedHere, errYieldNotAllowedInTryStmt,
-    errInvalidNumberOfYieldExpr, errCannotReturnExpr,
-    errNoReturnWithReturnTypeNotAllowed, errAttemptToRedefine,
-    errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel,
-    errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected,
-    errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler,
-    errOnOrOffExpectedButXFound, errOnOffOrListExpectedButXFound,
-    errNoneBoehmRefcExpectedButXFound,
-    errNoneSpeedOrSizeExpectedButXFound, errGuiConsoleOrLibExpectedButXFound,
-    errUnknownOS, errUnknownCPU, errGenOutExpectedButXFound,
-    errArgsNeedRunOption, errInvalidMultipleAsgn, errColonOrEqualsExpected,
-    errExprExpected, errUndeclaredField,
-    errUndeclaredRoutine, errUseQualifier,
-    errTypeExpected,
-    errSystemNeeds, errExecutionOfProgramFailed, errNotOverloadable,
-    errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue,
-    errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous,
-    errConstantDivisionByZero, errOrdinalTypeExpected,
-    errOrdinalOrFloatTypeExpected, errOverOrUnderflow,
-    errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255,
-    errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess,
-    errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType,
-    errValueOutOfSetBounds, errFieldInitTwice, errFieldNotInit,
-    errExprXCannotBeCalled, errExprHasNoType, errExprXHasNoType,
-    errCastNotInSafeMode, errExprCannotBeCastToX, errCommaOrParRiExpected,
-    errCurlyLeOrParLeExpected, errSectionExpected, errRangeExpected,
-    errMagicOnlyInSystem, errPowerOfTwoExpected,
-    errStringMayNotBeEmpty, errCallConvExpected, errProcOnlyOneCallConv,
-    errSymbolMustBeImported, errExprMustBeBool, errConstExprExpected,
-    errDuplicateCaseLabel, errRangeIsEmpty, errSelectorMustBeOfCertainTypes,
-    errSelectorMustBeOrdinal, errOrdXMustNotBeNegative, errLenXinvalid,
-    errWrongNumberOfVariables, errExprCannotBeRaised, errBreakOnlyInLoop,
-    errTypeXhasUnknownSize, errConstNeedsConstExpr, errConstNeedsValue,
-    errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig,
-    errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects,
-    errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX,
-    errCannotInstantiateX, errExprHasNoAddress, errXStackEscape,
-    errVarForOutParamNeededX,
-    errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX,
-    errAmbiguousCallXYZ, errWrongNumberOfArguments,
-    errWrongNumberOfArgumentsInCall,
-    errMissingGenericParamsForTemplate,
-    errXCannotBePassedToProcVar,
-    errPragmaOnlyInHeaderOfProcX, errImplOfXNotAllowed,
-    errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,
-    errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,
-    errInvalidOrderInArrayConstructor,
-    errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry,
-    errOptionExpected, errXisNoLabel, errNotAllCasesCovered,
-    errUnknownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable,
-    errNoPragmasAllowedForX, errNoGenericParamsAllowedForX,
-    errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent,
-    errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX,
-    errXNotAllowedHere, errInvalidControlFlowX,
-    errXisNoType, errCircumNeedsPointer, errInvalidExpression,
-    errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected,
-    errNamedExprNotAllowed, errXExpectsOneTypeParam,
-    errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed,
-    errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType,
-    errNoReturnTypeDeclared,
-    errNoCommand, errInvalidCommandX, errXOnlyAtModuleScope,
-    errXNeedsParamObjectType,
-    errTemplateInstantiationTooNested, errMacroInstantiationTooNested,
-    errInstantiationFrom,
-    errInvalidIndexValueForTuple, errCommandExpectsFilename,
-    errMainModuleMustBeSpecified,
-    errXExpected,
-    errTIsNotAConcreteType,
-    errCastToANonConcreteType,
-    errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
-    errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
-    errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly,
-    errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
-    errMacroBodyDependsOnGenericTypes,
-    errDestructorNotGenericEnough,
-    errInlineIteratorsAsProcParams,
-    errXExpectsTwoArguments,
-    errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations,
-    errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX,
-    errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument,
-    errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate,
-    errXhasSideEffects, errIteratorExpected, errLetNeedsInit,
-    errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX,
-    errXCannotBeClosure, errXMustBeCompileTime,
-    errCannotInferTypeOfTheLiteral,
-    errCannotInferReturnType,
-    errCannotInferStaticParam,
-    errGenericLambdaNotAllowed,
-    errProcHasNoConcreteType,
-    errCompilerDoesntSupportTarget,
-    errInOutFlagNotExtern,
-    errUser,
-    warnCannotOpenFile,
-    warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
-    warnDeprecated, warnConfigDeprecated,
-    warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
-    warnUnknownSubstitutionX, warnLanguageXNotSupported,
-    warnFieldXNotSupported, warnCommentXIgnored,
-    warnTypelessParam,
-    warnUseBase, warnWriteToForeignHeap, warnUnsafeCode,
-    warnEachIdentIsTuple, warnShadowIdent,
-    warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
-    warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
-    warnInconsistentSpacing, warnUser,
-    hintSuccess, hintSuccessX,
-    hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
-    hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
-    hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
-    hintConditionAlwaysTrue, hintName, hintPattern,
-    hintExecuting, hintLinking, hintDependency,
-    hintSource, hintPerformance, hintStackTrace, hintGCStats,
-    hintUser, hintUserRaw
-
-const
-  MsgKindToStr*: array[TMsgKind, string] = [
-    errUnknown: "unknown error",
-    errInternal: "internal error: $1",
-    errIllFormedAstX: "illformed AST: $1",
-    errCannotOpenFile: "cannot open '$1'",
-    errGenerated: "$1",
-    errStringLiteralExpected: "string literal expected",
-    errIntLiteralExpected: "integer literal expected",
-    errInvalidCharacterConstant: "invalid character constant",
-    errClosingTripleQuoteExpected: "closing \"\"\" expected, but end of file reached",
-    errClosingQuoteExpected: "closing \" expected",
-    errTabulatorsAreNotAllowed: "tabulators are not allowed",
-    errInvalidToken: "invalid token: $1",
-    errInvalidNumber: "$1 is not a valid number",
-    errInvalidNumberOctalCode: "$1 is not a valid number; did you mean octal? Then use one of '0o', '0c' or '0C'.",
-    errNumberOutOfRange: "number $1 out of valid range",
-    errNnotAllowedInCharacter: "\\n not allowed in character literal",
-    errClosingBracketExpected: "closing ']' expected, but end of file reached",
-    errMissingFinalQuote: "missing final ' for character literal",
-    errIdentifierExpected: "identifier expected, but found '$1'",
-    errNewlineExpected: "newline expected, but found '$1'",
-    errInvalidModuleName: "invalid module name: '$1'",
-    errOperatorExpected: "operator expected, but found '$1'",
-    errTokenExpected: "'$1' expected",
-    errRecursiveDependencyX: "recursive dependency: '$1'",
-    errOnOrOffExpected: "'on' or 'off' expected",
-    errNoneSpeedOrSizeExpected: "'none', 'speed' or 'size' expected",
-    errInvalidPragma: "invalid pragma",
-    errUnknownPragma: "unknown pragma: '$1'",
-    errInvalidDirectiveX: "invalid directive: '$1'",
-    errAtPopWithoutPush: "'pop' without a 'push' pragma",
-    errEmptyAsm: "empty asm statement",
-    errInvalidIndentation: "invalid indentation",
-    errExceptionAlreadyHandled: "exception already handled",
-    errYieldNotAllowedHere: "'yield' only allowed in an iterator",
-    errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlined iterator",
-    errInvalidNumberOfYieldExpr: "invalid number of 'yield' expressions",
-    errCannotReturnExpr: "current routine cannot return an expression",
-    errNoReturnWithReturnTypeNotAllowed: "routines with NoReturn pragma are not allowed to have return type",
-    errAttemptToRedefine: "redefinition of '$1'",
-    errStmtInvalidAfterReturn: "statement not allowed after 'return', 'break', 'raise', 'continue' or proc call with noreturn pragma",
-    errStmtExpected: "statement expected",
-    errInvalidLabel: "'$1' is no label",
-    errInvalidCmdLineOption: "invalid command line option: '$1'",
-    errCmdLineArgExpected: "argument for command line option expected: '$1'",
-    errCmdLineNoArgExpected: "invalid argument for command line option: '$1'",
-    errInvalidVarSubstitution: "invalid variable substitution in '$1'",
-    errUnknownVar: "unknown variable: '$1'",
-    errUnknownCcompiler: "unknown C compiler: '$1'",
-    errOnOrOffExpectedButXFound: "'on' or 'off' expected, but '$1' found",
-    errOnOffOrListExpectedButXFound: "'on', 'off' or 'list' expected, but '$1' found",
-    errNoneBoehmRefcExpectedButXFound: "'none', 'boehm' or 'refc' expected, but '$1' found",
-    errNoneSpeedOrSizeExpectedButXFound: "'none', 'speed' or 'size' expected, but '$1' found",
-    errGuiConsoleOrLibExpectedButXFound: "'gui', 'console' or 'lib' expected, but '$1' found",
-    errUnknownOS: "unknown OS: '$1'",
-    errUnknownCPU: "unknown CPU: '$1'",
-    errGenOutExpectedButXFound: "'c', 'c++' or 'yaml' expected, but '$1' found",
-    errArgsNeedRunOption: "arguments can only be given if the '--run' option is selected",
-    errInvalidMultipleAsgn: "multiple assignment is not allowed",
-    errColonOrEqualsExpected: "':' or '=' expected, but found '$1'",
-    errExprExpected: "expression expected, but found '$1'",
-    errUndeclaredField: "undeclared field: '$1'",
-    errUndeclaredRoutine: "attempting to call undeclared routine: '$1'",
-    errUseQualifier: "ambiguous identifier: '$1' -- use a qualifier",
-    errTypeExpected: "type expected",
-    errSystemNeeds: "system module needs '$1'",
-    errExecutionOfProgramFailed: "execution of an external program failed: '$1'",
-    errNotOverloadable: "overloaded '$1' leads to ambiguous calls",
-    errInvalidArgForX: "invalid argument for '$1'",
-    errStmtHasNoEffect: "statement has no effect",
-    errXExpectsTypeOrValue: "'$1' expects a type or value",
-    errXExpectsArrayType: "'$1' expects an array type",
-    errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet",
-    errExprXAmbiguous: "expression '$1' ambiguous in this context",
-    errConstantDivisionByZero: "division by zero",
-    errOrdinalTypeExpected: "ordinal type expected",
-    errOrdinalOrFloatTypeExpected: "ordinal or float type expected",
-    errOverOrUnderflow: "over- or underflow",
-    errCannotEvalXBecauseIncompletelyDefined: "cannot evaluate '$1' because type is not defined completely",
-    errChrExpectsRange0_255: "'chr' expects an int in the range 0..255",
-    errDynlibRequiresExportc: "'dynlib' requires 'exportc'",
-    errUndeclaredFieldX: "undeclared field: '$1'",
-    errNilAccess: "attempt to access a nil address",
-    errIndexOutOfBounds: "index out of bounds",
-    errIndexTypesDoNotMatch: "index types do not match",
-    errBracketsInvalidForType: "'[]' operator invalid for this type",
-    errValueOutOfSetBounds: "value out of set bounds",
-    errFieldInitTwice: "field initialized twice: '$1'",
-    errFieldNotInit: "field '$1' not initialized",
-    errExprXCannotBeCalled: "expression '$1' cannot be called",
-    errExprHasNoType: "expression has no type",
-    errExprXHasNoType: "expression '$1' has no type (or is ambiguous)",
-    errCastNotInSafeMode: "'cast' not allowed in safe mode",
-    errExprCannotBeCastToX: "expression cannot be cast to $1",
-    errCommaOrParRiExpected: "',' or ')' expected",
-    errCurlyLeOrParLeExpected: "'{' or '(' expected",
-    errSectionExpected: "section ('type', 'proc', etc.) expected",
-    errRangeExpected: "range expected",
-    errMagicOnlyInSystem: "'magic' only allowed in system module",
-    errPowerOfTwoExpected: "power of two expected",
-    errStringMayNotBeEmpty: "string literal may not be empty",
-    errCallConvExpected: "calling convention expected",
-    errProcOnlyOneCallConv: "a proc can only have one calling convention",
-    errSymbolMustBeImported: "symbol must be imported if 'lib' pragma is used",
-    errExprMustBeBool: "expression must be of type 'bool'",
-    errConstExprExpected: "constant expression expected",
-    errDuplicateCaseLabel: "duplicate case label",
-    errRangeIsEmpty: "range is empty",
-    errSelectorMustBeOfCertainTypes: "selector must be of an ordinal type, float or string",
-    errSelectorMustBeOrdinal: "selector must be of an ordinal type",
-    errOrdXMustNotBeNegative: "ord($1) must not be negative",
-    errLenXinvalid: "len($1) must be less than 32768",
-    errWrongNumberOfVariables: "wrong number of variables",
-    errExprCannotBeRaised: "only a 'ref object' can be raised",
-    errBreakOnlyInLoop: "'break' only allowed in loop construct",
-    errTypeXhasUnknownSize: "type '$1' has unknown size",
-    errConstNeedsConstExpr: "a constant can only be initialized with a constant expression",
-    errConstNeedsValue: "a constant needs a value",
-    errResultCannotBeOpenArray: "the result type cannot be on open array",
-    errSizeTooBig: "computing the type's size produced an overflow",
-    errSetTooBig: "set is too large",
-    errBaseTypeMustBeOrdinal: "base type of a set must be an ordinal",
-    errInheritanceOnlyWithNonFinalObjects: "inheritance only works with non-final objects",
-    errInheritanceOnlyWithEnums: "inheritance only works with an enum",
-    errIllegalRecursionInTypeX: "illegal recursion in type '$1'",
-    errCannotInstantiateX: "cannot instantiate: '$1'",
-    errExprHasNoAddress: "expression has no address",
-    errXStackEscape: "address of '$1' may not escape its stack frame",
-    errVarForOutParamNeededX: "for a 'var' type a variable needs to be passed; but '$1' is immutable",
-    errPureTypeMismatch: "type mismatch",
-    errTypeMismatch: "type mismatch: got <",
-    errButExpected: "but expected one of: ",
-    errButExpectedX: "but expected '$1'",
-    errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3",
-    errWrongNumberOfArguments: "wrong number of arguments",
-    errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'",
-    errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters",
-    errXCannotBePassedToProcVar: "'$1' cannot be passed to a procvar",
-    errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1",
-    errImplOfXNotAllowed: "implementation of '$1' is not allowed",
-    errImplOfXexpected: "implementation of '$1' expected",
-    errNoSymbolToBorrowFromFound: "no symbol to borrow from found",
-    errDiscardValueX: "value of type '$1' has to be discarded",
-    errInvalidDiscard: "statement returns no value that can be discarded",
-    errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid",
-    errCannotBindXTwice: "cannot bind parameter '$1' twice",
-    errInvalidOrderInArrayConstructor: "invalid order in array constructor",
-    errInvalidOrderInEnumX: "invalid order in enum '$1'",
-    errEnumXHasHoles: "enum '$1' has holes",
-    errExceptExpected: "'except' or 'finally' expected",
-    errInvalidTry: "after catch all 'except' or 'finally' no section may follow",
-    errOptionExpected: "option expected, but found '$1'",
-    errXisNoLabel: "'$1' is not a label",
-    errNotAllCasesCovered: "not all cases are covered",
-    errUnknownSubstitionVar: "unknown substitution variable: '$1'",
-    errComplexStmtRequiresInd: "complex statement requires indentation",
-    errXisNotCallable: "'$1' is not callable",
-    errNoPragmasAllowedForX: "no pragmas allowed for $1",
-    errNoGenericParamsAllowedForX: "no generic parameters allowed for $1",
-    errInvalidParamKindX: "invalid param kind: '$1'",
-    errDefaultArgumentInvalid: "default argument invalid",
-    errNamedParamHasToBeIdent: "named parameter has to be an identifier",
-    errNoReturnTypeForX: "no return type allowed for $1",
-    errConvNeedsOneArg: "a type conversion needs exactly one argument",
-    errInvalidPragmaX: "invalid pragma: $1",
-    errXNotAllowedHere: "$1 not allowed here",
-    errInvalidControlFlowX: "invalid control flow: $1",
-    errXisNoType: "invalid type: '$1'",
-    errCircumNeedsPointer: "'[]' needs a pointer or reference type",
-    errInvalidExpression: "invalid expression",
-    errInvalidExpressionX: "invalid expression: '$1'",
-    errEnumHasNoValueX: "enum has no value '$1'",
-    errNamedExprExpected: "named expression expected",
-    errNamedExprNotAllowed: "named expression not allowed here",
-    errXExpectsOneTypeParam: "'$1' expects one type parameter",
-    errArrayExpectsTwoTypeParams: "array expects two type parameters",
-    errInvalidVisibilityX: "invalid visibility: '$1'",
-    errInitHereNotAllowed: "initialization not allowed here",
-    errXCannotBeAssignedTo: "'$1' cannot be assigned to",
-    errIteratorNotAllowed: "iterators can only be defined at the module's top level",
-    errXNeedsReturnType: "$1 needs a return type",
-    errNoReturnTypeDeclared: "no return type declared",
-    errNoCommand: "no command given",
-    errInvalidCommandX: "invalid command: '$1'",
-    errXOnlyAtModuleScope: "'$1' is only allowed at top level",
-    errXNeedsParamObjectType: "'$1' needs a parameter that has an object type",
-    errTemplateInstantiationTooNested: "template instantiation too nested, try --evalTemplateLimit:N",
-    errMacroInstantiationTooNested: "macro instantiation too nested, try --evalMacroLimit:N",
-    errInstantiationFrom: "template/generic instantiation from here",
-    errInvalidIndexValueForTuple: "invalid index value for tuple subscript",
-    errCommandExpectsFilename: "command expects a filename argument",
-    errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file",
-    errXExpected: "'$1' expected",
-    errTIsNotAConcreteType: "'$1' is not a concrete type.",
-    errCastToANonConcreteType: "cannot cast to a non concrete type: '$1'",
-    errInvalidSectionStart: "invalid section start",
-    errGridTableNotImplemented: "grid table is not implemented",
-    errGeneralParseError: "general parse error",
-    errNewSectionExpected: "new section expected",
-    errWhitespaceExpected: "whitespace expected, got '$1'",
-    errXisNoValidIndexFile: "'$1' is no valid index file",
-    errCannotRenderX: "cannot render reStructuredText element '$1'",
-    errVarVarTypeNotAllowed: "type 'var var' is not allowed",
-    errInstantiateXExplicitly: "instantiate '$1' explicitly",
-    errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator",
-    errUsingNoSymbol: "'$1' is not a variable, constant or a proc name",
-    errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " &
-                                       "because the parameter '$1' has a generic type",
-    errDestructorNotGenericEnough: "Destructor signature is too specific. " &
-                                   "A destructor must be associated will all instantiations of a generic type",
-    errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " &
-                                    "templates, macros and other inline iterators",
-    errXExpectsTwoArguments: "'$1' expects two arguments",
-    errXExpectsObjectTypes: "'$1' expects object types",
-    errXcanNeverBeOfThisSubtype: "'$1' can never be of this subtype",
-    errTooManyIterations: "interpretation requires too many iterations; " &
-      "if you are sure this is not a bug in your code edit " &
-      "compiler/vmdef.MaxLoopIterations and rebuild the compiler",
-    errCannotInterpretNodeX: "cannot evaluate '$1'",
-    errFieldXNotFound: "field '$1' cannot be found",
-    errInvalidConversionFromTypeX: "invalid conversion from type '$1'",
-    errAssertionFailed: "assertion failed",
-    errCannotGenerateCodeForX: "cannot generate code for '$1'",
-    errXRequiresOneArgument: "$1 requires one parameter",
-    errUnhandledExceptionX: "unhandled exception: $1",
-    errCyclicTree: "macro returned a cyclic abstract syntax tree",
-    errXisNoMacroOrTemplate: "'$1' is no macro or template",
-    errXhasSideEffects: "'$1' can have side effects",
-    errIteratorExpected: "iterator within for loop context expected",
-    errLetNeedsInit: "'let' symbol requires an initialization",
-    errThreadvarCannotInit: "a thread var cannot be initialized explicitly; this would only run for the main thread",
-    errWrongSymbolX: "usage of '$1' is a user-defined error",
-    errIllegalCaptureX: "illegal capture '$1'",
-    errXCannotBeClosure: "'$1' cannot have 'closure' calling convention",
-    errXMustBeCompileTime: "'$1' can only be used in compile-time context",
-    errCannotInferTypeOfTheLiteral: "cannot infer the type of the $1",
-    errCannotInferReturnType: "cannot infer the return type of the proc",
-    errCannotInferStaticParam: "cannot infer the value of the static param `$1`",
-    errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " &
-                                "it is used as an operand to another routine and the types " &
-                                "of the generic paramers can be inferred from the expected signature.",
-    errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.",
-    errCompilerDoesntSupportTarget: "The current compiler '$1' doesn't support the requested compilation target",
-    errInOutFlagNotExtern: "The `$1` modifier can be used only with imported types",
-    errUser: "$1",
-    warnCannotOpenFile: "cannot open '$1'",
-    warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
-    warnXIsNeverRead: "'$1' is never read",
-    warnXmightNotBeenInit: "'$1' might not have been initialized",
-    warnDeprecated: "$1 is deprecated",
-    warnConfigDeprecated: "config file '$1' is deprecated",
-    warnSmallLshouldNotBeUsed: "'l' should not be used as an identifier; may look like '1' (one)",
-    warnUnknownMagic: "unknown magic '$1' might crash the compiler",
-    warnRedefinitionOfLabel: "redefinition of label '$1'",
-    warnUnknownSubstitutionX: "unknown substitution '$1'",
-    warnLanguageXNotSupported: "language '$1' not supported",
-    warnFieldXNotSupported: "field '$1' not supported",
-    warnCommentXIgnored: "comment '$1' ignored",
-    warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'",
-    warnUseBase: "use {.base.} for base methods; baseless methods are deprecated",
-    warnWriteToForeignHeap: "write to foreign heap",
-    warnUnsafeCode: "unsafe code: '$1'",
-    warnEachIdentIsTuple: "each identifier is a tuple",
-    warnShadowIdent: "shadowed identifier: '$1'",
-    warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future.",
-    warnProveField: "cannot prove that field '$1' is accessible",
-    warnProveIndex: "cannot prove index '$1' is valid",
-    warnGcUnsafe: "not GC-safe: '$1'",
-    warnGcUnsafe2: "$1",
-    warnUninit: "'$1' might not have been initialized",
-    warnGcMem: "'$1' uses GC'ed memory",
-    warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.",
-    warnLockLevel: "$1",
-    warnResultShadowed: "Special variable 'result' is shadowed.",
-    warnInconsistentSpacing: "Number of spaces around '$#' is not consistent",
-    warnUser: "$1",
-    hintSuccess: "operation successful",
-    hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)",
-    hintLineTooLong: "line too long",
-    hintXDeclaredButNotUsed: "'$1' is declared but not used",
-    hintConvToBaseNotNeeded: "conversion to base object is not needed",
-    hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless",
-    hintExprAlwaysX: "expression evaluates always to '$1'",
-    hintQuitCalled: "quit() called",
-    hintProcessing: "$1",
-    hintCodeBegin: "generated code listing:",
-    hintCodeEnd: "end of listing",
-    hintConf: "used config file '$1'",
-    hintPath: "added path: '$1'",
-    hintConditionAlwaysTrue: "condition is always true: '$1'",
-    hintName: "name should be: '$1'",
-    hintPattern: "$1",
-    hintExecuting: "$1",
-    hintLinking: "",
-    hintDependency: "$1",
-    hintSource: "$1",
-    hintPerformance: "$1",
-    hintStackTrace: "$1",
-    hintGCStats: "$1",
-    hintUser: "$1",
-    hintUserRaw: "$1"]
-
-const
-  WarningsToStr* = ["CannotOpenFile", "OctalEscape",
-    "XIsNeverRead", "XmightNotBeenInit",
-    "Deprecated", "ConfigDeprecated",
-    "SmallLshouldNotBeUsed", "UnknownMagic",
-    "RedefinitionOfLabel", "UnknownSubstitutionX",
-    "LanguageXNotSupported", "FieldXNotSupported",
-    "CommentXIgnored",
-    "TypelessParam", "UseBase", "WriteToForeignHeap",
-    "UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
-    "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
-    "GcMem", "Destructor", "LockLevel", "ResultShadowed",
-    "Spacing", "User"]
-
-  HintsToStr* = ["Success", "SuccessX", "LineTooLong",
-    "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
-    "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
-    "Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency",
-    "Source", "Performance", "StackTrace", "GCStats",
-    "User", "UserRaw"]
-
-const
-  fatalMin* = errUnknown
-  fatalMax* = errInternal
-  errMin* = errUnknown
-  errMax* = errUser
-  warnMin* = warnCannotOpenFile
-  warnMax* = pred(hintSuccess)
-  hintMin* = hintSuccess
-  hintMax* = high(TMsgKind)
-
-static:
-  doAssert HintsToStr.len == ord(hintMax) - ord(hintMin) + 1
-  doAssert WarningsToStr.len == ord(warnMax) - ord(warnMin) + 1
+#type
+#  MsgConfig* = ref object of RootObj
 
 type
-  TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
-  TNoteKinds* = set[TNoteKind]
-
   TFileInfo* = object
     fullPath: string           # This is a canonical full filesystem path
     projPath*: string          # This is relative to the project's root
@@ -527,35 +59,11 @@ type
 
 proc `==`*(a, b: FileIndex): bool {.borrow.}
 
-const
-  NotesVerbosity*: array[0..3, TNoteKinds] = [
-    {low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
-                                         warnProveField, warnProveIndex,
-                                         warnGcUnsafe,
-                                         hintSuccessX, hintPath, hintConf,
-                                         hintProcessing, hintPattern,
-                                         hintDependency,
-                                         hintExecuting, hintLinking,
-                                         hintCodeBegin, hintCodeEnd,
-                                         hintSource, hintStackTrace,
-                                         hintGCStats},
-    {low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
-                                         warnProveField, warnProveIndex,
-                                         warnGcUnsafe,
-                                         hintPath,
-                                         hintDependency,
-                                         hintCodeBegin, hintCodeEnd,
-                                         hintSource, hintStackTrace,
-                                         hintGCStats},
-    {low(TNoteKind)..high(TNoteKind)} - {hintStackTrace, warnUninit},
-    {low(TNoteKind)..high(TNoteKind)}]
 
 const
   InvalidFileIDX* = FileIndex(-1)
 
 var
-  ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic,
-    hintQuitCalled, hintExecuting}
   filenameToIndexTbl = initTable[string, FileIndex]()
   fileInfos*: seq[TFileInfo] = @[]
   systemFileIdx*: FileIndex
@@ -591,8 +99,7 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo =
   result.shortName = fileName.changeFileExt("")
   result.quotedName = fileName.makeCString
   result.quotedFullName = fullPath.makeCString
-  if optEmbedOrigSrc in gGlobalOptions or true:
-    result.lines = @[]
+  result.lines = @[]
   when defined(nimpretty):
     if result.fullPath.len > 0:
       try:
@@ -606,22 +113,22 @@ when defined(nimpretty):
   proc fileSection*(fid: FileIndex; a, b: int): string =
     substr(fileInfos[fid.int].fullContent, a, b)
 
-proc fileInfoKnown*(filename: string): bool =
+proc fileInfoKnown*(conf: ConfigRef; filename: string): bool =
   var
     canon: string
   try:
-    canon = canonicalizePath(filename)
+    canon = canonicalizePath(conf, filename)
   except:
     canon = filename
   result = filenameToIndexTbl.hasKey(canon)
 
-proc fileInfoIdx*(filename: string; isKnownFile: var bool): FileIndex =
+proc fileInfoIdx*(conf: ConfigRef; filename: string; isKnownFile: var bool): FileIndex =
   var
     canon: string
     pseudoPath = false
 
   try:
-    canon = canonicalizePath(filename)
+    canon = canonicalizePath(conf, filename)
     shallow(canon)
   except:
     canon = filename
@@ -635,39 +142,32 @@ proc fileInfoIdx*(filename: string; isKnownFile: var bool): FileIndex =
     isKnownFile = false
     result = fileInfos.len.FileIndex
     fileInfos.add(newFileInfo(canon, if pseudoPath: filename
-                                     else: canon.shortenDir))
+                                     else: shortenDir(conf, canon)))
     filenameToIndexTbl[canon] = result
 
-proc fileInfoIdx*(filename: string): FileIndex =
+proc fileInfoIdx*(conf: ConfigRef; filename: string): FileIndex =
   var dummy: bool
-  result = fileInfoIdx(filename, dummy)
+  result = fileInfoIdx(conf, filename, dummy)
 
 proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
   result.fileIndex = fileInfoIdx
   result.line = uint16(line)
   result.col = int16(col)
 
-proc newLineInfo*(filename: string, line, col: int): TLineInfo {.inline.} =
-  result = newLineInfo(filename.fileInfoIdx, line, col)
+proc newLineInfo*(conf: ConfigRef; filename: string, line, col: int): TLineInfo {.inline.} =
+  result = newLineInfo(fileInfoIdx(conf, filename), line, col)
 
-fileInfos.add(newFileInfo("", "command line"))
-var gCmdLineInfo* = newLineInfo(FileIndex(0), 1, 1)
+when false:
+  fileInfos.add(newFileInfo("", "command line"))
+  var gCmdLineInfo* = newLineInfo(FileIndex(0), 1, 1)
 
-fileInfos.add(newFileInfo("", "compilation artifact"))
-var gCodegenLineInfo* = newLineInfo(FileIndex(1), 1, 1)
+  fileInfos.add(newFileInfo("", "compilation artifact"))
+  var gCodegenLineInfo* = newLineInfo(FileIndex(1), 1, 1)
 
 proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
   raise newException(ERecoverableError, msg)
 
-proc sourceLine*(i: TLineInfo): Rope
-
-var
-  gNotes*: TNoteKinds = NotesVerbosity[1] # defaults to verbosity of 1
-  gErrorCounter*: int = 0     # counts the number of errors
-  gHintCounter*: int = 0
-  gWarnCounter*: int = 0
-  gErrorMax*: int = 1         # stop after gErrorMax errors
-  gMainPackageNotes*: TNoteKinds = NotesVerbosity[1]
+proc sourceLine*(conf: ConfigRef; i: TLineInfo): Rope
 
 proc unknownLineInfo*(): TLineInfo =
   result.line = uint16(0)
@@ -767,10 +267,10 @@ template toFilename*(info: TLineInfo): string =
 template toFullPath*(info: TLineInfo): string =
   info.fileIndex.toFullPath
 
-proc toMsgFilename*(info: TLineInfo): string =
+proc toMsgFilename*(conf: ConfigRef; info: TLineInfo): string =
   if info.fileIndex.int32 < 0:
     result = "???"
-  elif gListFullPaths:
+  elif optListFullPaths in conf.globalOptions:
     result = fileInfos[info.fileIndex.int32].fullPath
   else:
     result = fileInfos[info.fileIndex.int32].projPath
@@ -805,7 +305,7 @@ type
     msgSkipHook    ## skip message hook even if it is present
   MsgFlags* = set[MsgFlag]
 
-proc msgWriteln*(s: string, flags: MsgFlags = {}) =
+proc msgWriteln*(conf: ConfigRef; s: string, flags: MsgFlags = {}) =
   ## Writes given message string to stderr by default.
   ## If ``--stdout`` option is given, writes to stdout instead. If message hook
   ## is present, then it is used to output message rather than stderr/stdout.
@@ -813,11 +313,11 @@ proc msgWriteln*(s: string, flags: MsgFlags = {}) =
 
   ## This is used for 'nim dump' etc. where we don't have nimsuggest
   ## support.
-  #if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
+  #if conf.cmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
 
   if not isNil(writelnHook) and msgSkipHook notin flags:
     writelnHook(s)
-  elif optStdout in gGlobalOptions or msgStdout in flags:
+  elif optStdout in conf.globalOptions or msgStdout in flags:
     if eStdOut in errorOutputs:
       writeLine(stdout, s)
       flushFile(stdout)
@@ -858,13 +358,13 @@ template callWritelnHook(args: varargs[string, `$`]) =
 template styledMsgWriteln*(args: varargs[typed]) =
   if not isNil(writelnHook):
     callIgnoringStyle(callWritelnHook, nil, args)
-  elif optStdout in gGlobalOptions:
+  elif optStdout in conf.globalOptions:
     if eStdOut in errorOutputs:
       callIgnoringStyle(writeLine, stdout, args)
       flushFile(stdout)
   else:
     if eStdErr in errorOutputs:
-      if optUseColors in gGlobalOptions:
+      if optUseColors in conf.globalOptions:
         callStyledWriteLineStderr(args)
       else:
         callIgnoringStyle(writeLine, stderr, args)
@@ -892,27 +392,27 @@ proc log*(s: string) {.procvar.} =
     f.writeLine(s)
     close(f)
 
-proc quit(msg: TMsgKind) =
-  if defined(debug) or msg == errInternal or hintStackTrace in gNotes:
+proc quit(conf: ConfigRef; msg: TMsgKind) =
+  if defined(debug) or msg == errInternal or hintStackTrace in conf.notes:
     if stackTraceAvailable() and isNil(writelnHook):
       writeStackTrace()
     else:
       styledMsgWriteln(fgRed, "No stack traceback available\n" &
           "To create a stacktrace, rerun compilation with ./koch temp " &
-          options.command & " <file>")
+          conf.command & " <file>")
   quit 1
 
-proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
+proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string) =
   if msg >= fatalMin and msg <= fatalMax:
-    if gCmd == cmdIdeTools: log(s)
-    quit(msg)
+    if conf.cmd == cmdIdeTools: log(s)
+    quit(conf, msg)
   if msg >= errMin and msg <= errMax:
-    inc(gErrorCounter)
-    options.gExitcode = 1'i8
-    if gErrorCounter >= gErrorMax:
-      quit(msg)
-    elif eh == doAbort and gCmd != cmdIdeTools:
-      quit(msg)
+    inc(conf.errorCounter)
+    conf.exitcode = 1'i8
+    if conf.errorCounter >= conf.errorMax:
+      quit(conf, msg)
+    elif eh == doAbort and conf.cmd != cmdIdeTools:
+      quit(conf, msg)
     elif eh == doRaise:
       raiseRecoverableError(s)
 
@@ -922,26 +422,27 @@ proc `==`*(a, b: TLineInfo): bool =
 proc exactEquals*(a, b: TLineInfo): bool =
   result = a.fileIndex == b.fileIndex and a.line == b.line and a.col == b.col
 
-proc writeContext(lastinfo: TLineInfo) =
+proc writeContext(conf: ConfigRef; lastinfo: TLineInfo) =
+  const instantiationFrom = "template/generic instantiation from here"
   var info = lastinfo
   for i in countup(0, len(msgContext) - 1):
     if msgContext[i] != lastinfo and msgContext[i] != info:
       if structuredErrorHook != nil:
-        structuredErrorHook(msgContext[i], getMessageStr(errInstantiationFrom, ""),
+        structuredErrorHook(msgContext[i], instantiationFrom,
                             Severity.Error)
       else:
         styledMsgWriteln(styleBright,
-                         PosFormat % [toMsgFilename(msgContext[i]),
+                         PosFormat % [toMsgFilename(conf, msgContext[i]),
                                       coordToStr(msgContext[i].line.int),
                                       coordToStr(msgContext[i].col+1)],
                          resetStyle,
-                         getMessageStr(errInstantiationFrom, ""))
+                         instantiationFrom)
     info = msgContext[i]
 
-proc ignoreMsgBecauseOfIdeTools(msg: TMsgKind): bool =
-  msg >= errGenerated and gCmd == cmdIdeTools and optIdeDebug notin gGlobalOptions
+proc ignoreMsgBecauseOfIdeTools(conf: ConfigRef; msg: TMsgKind): bool =
+  msg >= errGenerated and conf.cmd == cmdIdeTools and optIdeDebug notin conf.globalOptions
 
-proc rawMessage*(msg: TMsgKind, args: openArray[string]) =
+proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) =
   var
     title: string
     color: ForegroundColor
@@ -950,62 +451,62 @@ proc rawMessage*(msg: TMsgKind, args: openArray[string]) =
   case msg
   of errMin..errMax:
     sev = Severity.Error
-    writeContext(unknownLineInfo())
+    writeContext(conf, unknownLineInfo())
     title = ErrorTitle
     color = ErrorColor
   of warnMin..warnMax:
     sev = Severity.Warning
-    if optWarns notin gOptions: return
-    if msg notin gNotes: return
-    writeContext(unknownLineInfo())
+    if optWarns notin conf.options: return
+    if msg notin conf.notes: return
+    writeContext(conf, unknownLineInfo())
     title = WarningTitle
     color = WarningColor
     kind = WarningsToStr[ord(msg) - ord(warnMin)]
-    inc(gWarnCounter)
+    inc(conf.warnCounter)
   of hintMin..hintMax:
     sev = Severity.Hint
-    if optHints notin gOptions: return
-    if msg notin gNotes: return
+    if optHints notin conf.options: return
+    if msg notin conf.notes: return
     title = HintTitle
     color = HintColor
     if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)]
-    inc(gHintCounter)
+    inc(conf.hintCounter)
   let s = msgKindToString(msg) % args
 
   if structuredErrorHook != nil:
     structuredErrorHook(unknownLineInfo(), s & (if kind != nil: KindFormat % kind else: ""), sev)
 
-  if not ignoreMsgBecauseOfIdeTools(msg):
+  if not ignoreMsgBecauseOfIdeTools(conf, msg):
     if kind != nil:
       styledMsgWriteln(color, title, resetStyle, s,
                        KindColor, `%`(KindFormat, kind))
     else:
       styledMsgWriteln(color, title, resetStyle, s)
-  handleError(msg, doAbort, s)
+  handleError(conf, msg, doAbort, s)
 
-proc rawMessage*(msg: TMsgKind, arg: string) =
-  rawMessage(msg, [arg])
+proc rawMessage*(conf: ConfigRef; msg: TMsgKind, arg: string) =
+  rawMessage(conf, msg, [arg])
 
-proc resetAttributes* =
-  if {optUseColors, optStdout} * gGlobalOptions == {optUseColors}:
+proc resetAttributes*(conf: ConfigRef) =
+  if {optUseColors, optStdout} * conf.globalOptions == {optUseColors}:
     terminal.resetAttributes(stderr)
 
-proc writeSurroundingSrc(info: TLineInfo) =
+proc writeSurroundingSrc(conf: ConfigRef; info: TLineInfo) =
   const indent = "  "
-  msgWriteln(indent & $info.sourceLine)
-  msgWriteln(indent & spaces(info.col) & '^')
+  msgWriteln(conf, indent & $sourceLine(conf, info))
+  msgWriteln(conf, indent & spaces(info.col) & '^')
 
-proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
+proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): string =
   let title = case msg
               of warnMin..warnMax: WarningTitle
               of hintMin..hintMax: HintTitle
               else: ErrorTitle
-  result = PosFormat % [toMsgFilename(info), coordToStr(info.line.int),
+  result = PosFormat % [toMsgFilename(conf, info), coordToStr(info.line.int),
                         coordToStr(info.col+1)] &
            title &
            getMessageStr(msg, arg)
 
-proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
+proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
                eh: TErrorHandling) =
   var
     title: string
@@ -1016,7 +517,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
   case msg
   of errMin..errMax:
     sev = Severity.Error
-    writeContext(info)
+    writeContext(conf, info)
     title = ErrorTitle
     color = ErrorColor
     # we try to filter error messages so that not two error message
@@ -1025,101 +526,101 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
     lastError = info
   of warnMin..warnMax:
     sev = Severity.Warning
-    ignoreMsg = optWarns notin gOptions or msg notin gNotes
-    if not ignoreMsg: writeContext(info)
+    ignoreMsg = optWarns notin conf.options or msg notin conf.notes
+    if not ignoreMsg: writeContext(conf, info)
     title = WarningTitle
     color = WarningColor
     kind = WarningsToStr[ord(msg) - ord(warnMin)]
-    inc(gWarnCounter)
+    inc(conf.warnCounter)
   of hintMin..hintMax:
     sev = Severity.Hint
-    ignoreMsg = optHints notin gOptions or msg notin gNotes
+    ignoreMsg = optHints notin conf.options or msg notin conf.notes
     title = HintTitle
     color = HintColor
     if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)]
-    inc(gHintCounter)
+    inc(conf.hintCounter)
   # NOTE: currently line info line numbers start with 1,
   # but column numbers start with 0, however most editors expect
   # first column to be 1, so we need to +1 here
-  let x = PosFormat % [toMsgFilename(info), coordToStr(info.line.int),
+  let x = PosFormat % [toMsgFilename(conf, info), coordToStr(info.line.int),
                        coordToStr(info.col+1)]
   let s = getMessageStr(msg, arg)
 
   if not ignoreMsg:
     if structuredErrorHook != nil:
       structuredErrorHook(info, s & (if kind != nil: KindFormat % kind else: ""), sev)
-    if not ignoreMsgBecauseOfIdeTools(msg):
+    if not ignoreMsgBecauseOfIdeTools(conf, msg):
       if kind != nil:
         styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s,
                          KindColor, `%`(KindFormat, kind))
       else:
         styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s)
-      if hintSource in gNotes:
-        info.writeSurroundingSrc
-  handleError(msg, eh, s)
+      if hintSource in conf.notes:
+        conf.writeSurroundingSrc(info)
+  handleError(conf, msg, eh, s)
 
-proc fatal*(info: TLineInfo, msg: TMsgKind, arg = "") =
+proc fatal*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
   # this fixes bug #7080 so that it is at least obvious 'fatal'
   # was executed.
   errorOutputs = {eStdOut, eStdErr}
-  liMessage(info, msg, arg, doAbort)
+  liMessage(conf, info, msg, arg, doAbort)
 
-proc globalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
-  liMessage(info, msg, arg, doRaise)
+proc globalError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
+  liMessage(conf, info, msg, arg, doRaise)
 
-proc globalError*(info: TLineInfo, arg: string) =
-  liMessage(info, errGenerated, arg, doRaise)
+proc globalError*(conf: ConfigRef; info: TLineInfo, arg: string) =
+  liMessage(conf, info, errGenerated, arg, doRaise)
 
-proc localError*(info: TLineInfo, msg: TMsgKind, arg = "") =
-  liMessage(info, msg, arg, doNothing)
+proc localError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
+  liMessage(conf, info, msg, arg, doNothing)
 
-proc localError*(info: TLineInfo, arg: string) =
-  liMessage(info, errGenerated, arg, doNothing)
+proc localError*(conf: ConfigRef; info: TLineInfo, arg: string) =
+  liMessage(conf, info, errGenerated, arg, doNothing)
 
-proc localError*(info: TLineInfo, format: string, params: openarray[string]) =
-  localError(info, format % params)
+proc localError*(conf: ConfigRef; info: TLineInfo, format: string, params: openarray[string]) =
+  localError(conf, info, format % params)
 
-proc message*(info: TLineInfo, msg: TMsgKind, arg = "") =
-  liMessage(info, msg, arg, doNothing)
+proc message*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
+  liMessage(conf, info, msg, arg, doNothing)
 
-proc internalError*(info: TLineInfo, errMsg: string) =
-  if gCmd == cmdIdeTools and structuredErrorHook.isNil: return
-  writeContext(info)
-  liMessage(info, errInternal, errMsg, doAbort)
+proc internalError*(conf: ConfigRef; info: TLineInfo, errMsg: string) =
+  if conf.cmd == cmdIdeTools and structuredErrorHook.isNil: return
+  writeContext(conf, info)
+  liMessage(conf, info, errInternal, errMsg, doAbort)
 
-proc internalError*(errMsg: string) =
-  if gCmd == cmdIdeTools and structuredErrorHook.isNil: return
-  writeContext(unknownLineInfo())
-  rawMessage(errInternal, errMsg)
+proc internalError*(conf: ConfigRef; errMsg: string) =
+  if conf.cmd == cmdIdeTools and structuredErrorHook.isNil: return
+  writeContext(conf, unknownLineInfo())
+  rawMessage(conf, errInternal, errMsg)
 
-template assertNotNil*(e): untyped =
-  if e == nil: internalError($instantiationInfo())
+template assertNotNil*(conf: ConfigRef; e): untyped =
+  if e == nil: internalError(conf, $instantiationInfo())
   e
 
-template internalAssert*(e: bool) =
-  if not e: internalError($instantiationInfo())
+template internalAssert*(conf: ConfigRef, e: bool) =
+  if not e: internalError(conf, $instantiationInfo())
 
 proc addSourceLine*(fileIdx: FileIndex, line: string) =
   fileInfos[fileIdx.int32].lines.add line.rope
 
-proc sourceLine*(i: TLineInfo): Rope =
+proc sourceLine*(conf: ConfigRef; i: TLineInfo): Rope =
   if i.fileIndex.int32 < 0: return nil
 
-  if not optPreserveOrigSource and fileInfos[i.fileIndex.int32].lines.len == 0:
+  if not optPreserveOrigSource(conf) and fileInfos[i.fileIndex.int32].lines.len == 0:
     try:
       for line in lines(i.toFullPath):
         addSourceLine i.fileIndex, line.string
     except IOError:
       discard
-  internalAssert i.fileIndex.int32 < fileInfos.len
+  assert i.fileIndex.int32 < fileInfos.len
   # can happen if the error points to EOF:
   if i.line.int > fileInfos[i.fileIndex.int32].lines.len: return nil
 
   result = fileInfos[i.fileIndex.int32].lines[i.line.int-1]
 
-proc quotedFilename*(i: TLineInfo): Rope =
-  internalAssert i.fileIndex.int32 >= 0
-  if optExcessiveStackTrace in gGlobalOptions:
+proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
+  assert i.fileIndex.int32 >= 0
+  if optExcessiveStackTrace in conf.globalOptions:
     result = fileInfos[i.fileIndex.int32].quotedFullName
   else:
     result = fileInfos[i.fileIndex.int32].quotedName
@@ -1127,26 +628,22 @@ proc quotedFilename*(i: TLineInfo): Rope =
 ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) =
   case err
   of rInvalidFormatStr:
-    internalError("ropes: invalid format string: " & msg)
+    internalError(newPartialConfigRef(), "ropes: invalid format string: " & msg)
   of rCannotOpenFile:
-    rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg)
+    rawMessage(newPartialConfigRef(), if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg)
 
-proc listWarnings*() =
-  msgWriteln("Warnings:")
+proc listWarnings*(conf: ConfigRef) =
+  msgWriteln(conf, "Warnings:")
   for warn in warnMin..warnMax:
-    msgWriteln("  [$1] $2" % [
-      if warn in gNotes: "x" else: " ",
-      msgs.WarningsToStr[ord(warn) - ord(warnMin)]
+    msgWriteln(conf, "  [$1] $2" % [
+      if warn in conf.notes: "x" else: " ",
+      configuration.WarningsToStr[ord(warn) - ord(warnMin)]
     ])
 
-proc listHints*() =
-  msgWriteln("Hints:")
+proc listHints*(conf: ConfigRef) =
+  msgWriteln(conf, "Hints:")
   for hint in hintMin..hintMax:
-    msgWriteln("  [$1] $2" % [
-      if hint in gNotes: "x" else: " ",
-      msgs.HintsToStr[ord(hint) - ord(hintMin)]
+    msgWriteln(conf, "  [$1] $2" % [
+      if hint in conf.notes: "x" else: " ",
+      configuration.HintsToStr[ord(hint) - ord(hintMin)]
     ])
-
-# enable colors by default on terminals
-if terminal.isatty(stderr):
-  incl(gGlobalOptions, optUseColors)
diff --git a/compiler/nim.nim b/compiler/nim.nim
index 280782330..d3e00017f 100644
--- a/compiler/nim.nim
+++ b/compiler/nim.nim
@@ -21,7 +21,7 @@ when defined(i386) and defined(windows) and defined(vcc):
 import
   commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
   extccomp, strutils, os, osproc, platform, main, parseopt, service,
-  nodejs, scriptconfig, idents, modulegraphs
+  nodejs, scriptconfig, idents, modulegraphs, configuration
 
 when hasTinyCBackend:
   import tccgen
@@ -37,69 +37,70 @@ proc prependCurDir(f: string): string =
   else:
     result = f
 
-proc handleCmdLine(cache: IdentCache; config: ConfigRef) =
+proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
+  condsyms.initDefines(conf.symbols)
   if paramCount() == 0:
-    writeCommandLineUsage()
+    writeCommandLineUsage(conf, conf.helpWritten)
   else:
     # Process command line arguments:
-    processCmdLine(passCmd1, "", config)
-    if gProjectName == "-":
-      gProjectName = "stdinfile"
-      gProjectFull = "stdinfile"
-      gProjectPath = canonicalizePath getCurrentDir()
-      gProjectIsStdin = true
-    elif gProjectName != "":
+    processCmdLine(passCmd1, "", conf)
+    if conf.projectName == "-":
+      conf.projectName = "stdinfile"
+      conf.projectFull = "stdinfile"
+      conf.projectPath = canonicalizePath(conf, getCurrentDir())
+      conf.projectIsStdin = true
+    elif conf.projectName != "":
       try:
-        gProjectFull = canonicalizePath(gProjectName)
+        conf.projectFull = canonicalizePath(conf, conf.projectName)
       except OSError:
-        gProjectFull = gProjectName
-      let p = splitFile(gProjectFull)
+        conf.projectFull = conf.projectName
+      let p = splitFile(conf.projectFull)
       let dir = if p.dir.len > 0: p.dir else: getCurrentDir()
-      gProjectPath = canonicalizePath dir
-      gProjectName = p.name
+      conf.projectPath = canonicalizePath(conf, dir)
+      conf.projectName = p.name
     else:
-      gProjectPath = canonicalizePath getCurrentDir()
-    loadConfigs(DefaultConfig, config) # load all config files
-    let scriptFile = gProjectFull.changeFileExt("nims")
+      conf.projectPath = canonicalizePath(conf, getCurrentDir())
+    loadConfigs(DefaultConfig, conf) # load all config files
+    let scriptFile = conf.projectFull.changeFileExt("nims")
     if fileExists(scriptFile):
-      runNimScript(cache, scriptFile, freshDefines=false, config)
+      runNimScript(cache, scriptFile, freshDefines=false, conf)
       # 'nim foo.nims' means to just run the NimScript file and do nothing more:
-      if scriptFile == gProjectFull: return
-    elif fileExists(gProjectPath / "config.nims"):
+      if scriptFile == conf.projectFull: return
+    elif fileExists(conf.projectPath / "config.nims"):
       # directory wide NimScript file
-      runNimScript(cache, gProjectPath / "config.nims", freshDefines=false, config)
+      runNimScript(cache, conf.projectPath / "config.nims", freshDefines=false, conf)
     # now process command line arguments again, because some options in the
     # command line can overwite the config file's settings
-    extccomp.initVars()
-    processCmdLine(passCmd2, "", config)
-    if options.command == "":
-      rawMessage(errNoCommand, command)
-    mainCommand(newModuleGraph(config), cache)
-    if optHints in gOptions and hintGCStats in gNotes: echo(GC_getStatistics())
+    extccomp.initVars(conf)
+    processCmdLine(passCmd2, "", conf)
+    if conf.command == "":
+      rawMessage(conf, errGenerated, "command missing")
+    mainCommand(newModuleGraph(conf), cache)
+    if optHints in conf.options and hintGCStats in conf.notes: echo(GC_getStatistics())
     #echo(GC_getStatistics())
-    if msgs.gErrorCounter == 0:
+    if conf.errorCounter == 0:
       when hasTinyCBackend:
-        if gCmd == cmdRun:
-          tccgen.run(config.arguments)
-      if optRun in gGlobalOptions:
-        if gCmd == cmdCompileToJS:
+        if conf.cmd == cmdRun:
+          tccgen.run(conf.arguments)
+      if optRun in conf.globalOptions:
+        if conf.cmd == cmdCompileToJS:
           var ex: string
-          if options.outFile.len > 0:
-            ex = options.outFile.prependCurDir.quoteShell
+          if conf.outFile.len > 0:
+            ex = conf.outFile.prependCurDir.quoteShell
           else:
             ex = quoteShell(
-              completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
-          execExternalProgram(findNodeJs() & " " & ex & ' ' & config.arguments)
+              completeCFilePath(conf, changeFileExt(conf.projectFull, "js").prependCurDir))
+          execExternalProgram(conf, findNodeJs() & " " & ex & ' ' & conf.arguments)
         else:
           var binPath: string
-          if options.outFile.len > 0:
+          if conf.outFile.len > 0:
             # If the user specified an outFile path, use that directly.
-            binPath = options.outFile.prependCurDir
+            binPath = conf.outFile.prependCurDir
           else:
             # Figure out ourselves a valid binary name.
-            binPath = changeFileExt(gProjectFull, ExeExt).prependCurDir
+            binPath = changeFileExt(conf.projectFull, ExeExt).prependCurDir
           var ex = quoteShell(binPath)
-          execExternalProgram(ex & ' ' & config.arguments)
+          execExternalProgram(conf, ex & ' ' & conf.arguments)
 
 when declared(GC_setMaxPause):
   GC_setMaxPause 2_000
@@ -107,10 +108,10 @@ when declared(GC_setMaxPause):
 when compileOption("gc", "v2") or compileOption("gc", "refc"):
   # the new correct mark&sweet collector is too slow :-/
   GC_disableMarkAndSweep()
-condsyms.initDefines()
 
 when not defined(selftest):
-  handleCmdLine(newIdentCache(), newConfigRef())
+  let conf = newConfigRef()
+  handleCmdLine(newIdentCache(), conf)
   when declared(GC_setMaxPause):
     echo GC_getStatistics()
-  msgQuit(int8(msgs.gErrorCounter > 0))
+  msgQuit(int8(conf.errorCounter > 0))
diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim
index 0f9e03352..8305b01f5 100644
--- a/compiler/nimblecmd.nim
+++ b/compiler/nimblecmd.nim
@@ -9,11 +9,12 @@
 
 ## Implements some helper procs for Nimble (Nim's package manager) support.
 
-import parseutils, strutils, strtabs, os, options, msgs, sequtils
+import parseutils, strutils, strtabs, os, options, msgs, sequtils,
+  configuration
 
-proc addPath*(path: string, info: TLineInfo) =
-  if not options.searchPaths.contains(path):
-    options.searchPaths.insert(path, 0)
+proc addPath*(conf: ConfigRef; path: string, info: TLineInfo) =
+  if not conf.searchPaths.contains(path):
+    conf.searchPaths.insert(path, 0)
 
 type
   Version* = distinct string
@@ -84,7 +85,7 @@ proc getPathVersion*(p: string): tuple[name, version: string] =
   result.name = p[0 .. sepIdx - 1]
   result.version = p.substr(sepIdx + 1)
 
-proc addPackage(packages: StringTableRef, p: string; info: TLineInfo) =
+proc addPackage(conf: ConfigRef; packages: StringTableRef, p: string; info: TLineInfo) =
   let (name, ver) = getPathVersion(p)
   if isValidVersion(ver):
     let version = newVersion(ver)
@@ -92,14 +93,14 @@ proc addPackage(packages: StringTableRef, p: string; info: TLineInfo) =
       (not packages.hasKey(name)):
       packages[name] = $version
   else:
-    localError(info, "invalid package name: " & p)
+    localError(conf, info, "invalid package name: " & p)
 
 iterator chosen(packages: StringTableRef): string =
   for key, val in pairs(packages):
     let res = if val.len == 0: key else: key & '-' & val
     yield res
 
-proc addNimblePath(p: string, info: TLineInfo) =
+proc addNimblePath(conf: ConfigRef; p: string, info: TLineInfo) =
   var path = p
   let nimbleLinks = toSeq(walkPattern(p / "*.nimble-link"))
   if nimbleLinks.len > 0:
@@ -111,23 +112,23 @@ proc addNimblePath(p: string, info: TLineInfo) =
     if not path.isAbsolute():
       path = p / path
 
-  if not contains(options.searchPaths, path):
-    message(info, hintPath, path)
-    options.lazyPaths.insert(path, 0)
+  if not contains(conf.searchPaths, path):
+    message(conf, info, hintPath, path)
+    conf.lazyPaths.insert(path, 0)
 
-proc addPathRec(dir: string, info: TLineInfo) =
+proc addPathRec(conf: ConfigRef; dir: string, info: TLineInfo) =
   var packages = newStringTable(modeStyleInsensitive)
   var pos = dir.len-1
   if dir[pos] in {DirSep, AltSep}: inc(pos)
   for k,p in os.walkDir(dir):
     if k == pcDir and p[pos] != '.':
-      addPackage(packages, p, info)
+      addPackage(conf, packages, p, info)
   for p in packages.chosen:
-    addNimblePath(p, info)
+    addNimblePath(conf, p, info)
 
-proc nimblePath*(path: string, info: TLineInfo) =
-  addPathRec(path, info)
-  addNimblePath(path, info)
+proc nimblePath*(conf: ConfigRef; path: string, info: TLineInfo) =
+  addPathRec(conf, path, info)
+  addNimblePath(conf, path, info)
 
 when isMainModule:
   proc v(s: string): Version = s.newVersion
diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim
index dc8d082b3..6cb5bab0f 100644
--- a/compiler/nimconf.nim
+++ b/compiler/nimconf.nim
@@ -11,7 +11,7 @@
 
 import
   llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer,
-  options, idents, wordrecg, strtabs
+  options, idents, wordrecg, strtabs, configuration
 
 # ---------------- configuration file parser -----------------------------
 # we use Nim's scanner here to save space and work
@@ -27,12 +27,12 @@ proc parseAtom(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
     ppGetTok(L, tok)
     result = parseExpr(L, tok, config)
     if tok.tokType == tkParRi: ppGetTok(L, tok)
-    else: lexMessage(L, errTokenExpected, "\')\'")
+    else: lexMessage(L, errGenerated, "expected closing ')'")
   elif tok.ident.id == ord(wNot):
     ppGetTok(L, tok)
     result = not parseAtom(L, tok, config)
   else:
-    result = isDefined(tok.ident)
+    result = isDefined(config, tok.ident.s)
     ppGetTok(L, tok)
 
 proc parseAndExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
@@ -53,12 +53,12 @@ proc evalppIf(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
   ppGetTok(L, tok)            # skip 'if' or 'elif'
   result = parseExpr(L, tok, config)
   if tok.tokType == tkColon: ppGetTok(L, tok)
-  else: lexMessage(L, errTokenExpected, "\':\'")
+  else: lexMessage(L, errGenerated, "expected ':'")
 
-var condStack: seq[bool] = @[]
+#var condStack: seq[bool] = @[]
 
-proc doEnd(L: var TLexer, tok: var TToken) =
-  if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
+proc doEnd(L: var TLexer, tok: var TToken; condStack: var seq[bool]) =
+  if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if")
   ppGetTok(L, tok)            # skip 'end'
   setLen(condStack, high(condStack))
 
@@ -66,20 +66,22 @@ type
   TJumpDest = enum
     jdEndif, jdElseEndif
 
-proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef)
-proc doElse(L: var TLexer, tok: var TToken; config: ConfigRef) =
-  if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
+proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef;
+                     condStack: var seq[bool])
+proc doElse(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
+  if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if")
   ppGetTok(L, tok)
   if tok.tokType == tkColon: ppGetTok(L, tok)
-  if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif, config)
+  if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif, config, condStack)
 
-proc doElif(L: var TLexer, tok: var TToken; config: ConfigRef) =
-  if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
+proc doElif(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
+  if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if")
   var res = evalppIf(L, tok, config)
-  if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif, config)
+  if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif, config, condStack)
   else: condStack[high(condStack)] = true
 
-proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef) =
+proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef;
+                     condStack: var seq[bool]) =
   var nestedIfs = 0
   while true:
     if tok.ident != nil and tok.ident.s == "@":
@@ -89,39 +91,39 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: Co
         inc(nestedIfs)
       of wElse:
         if dest == jdElseEndif and nestedIfs == 0:
-          doElse(L, tok, config)
+          doElse(L, tok, config, condStack)
           break
       of wElif:
         if dest == jdElseEndif and nestedIfs == 0:
-          doElif(L, tok, config)
+          doElif(L, tok, config, condStack)
           break
       of wEnd:
         if nestedIfs == 0:
-          doEnd(L, tok)
+          doEnd(L, tok, condStack)
           break
         if nestedIfs > 0: dec(nestedIfs)
       else:
         discard
       ppGetTok(L, tok)
     elif tok.tokType == tkEof:
-      lexMessage(L, errTokenExpected, "@end")
+      lexMessage(L, errGenerated, "expected @end")
     else:
       ppGetTok(L, tok)
 
-proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef) =
+proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
   ppGetTok(L, tok)            # skip @
   case whichKeyword(tok.ident)
   of wIf:
     setLen(condStack, len(condStack) + 1)
     let res = evalppIf(L, tok, config)
     condStack[high(condStack)] = res
-    if not res: jumpToDirective(L, tok, jdElseEndif, config)
-  of wElif: doElif(L, tok, config)
-  of wElse: doElse(L, tok, config)
-  of wEnd: doEnd(L, tok)
+    if not res: jumpToDirective(L, tok, jdElseEndif, config, condStack)
+  of wElif: doElif(L, tok, config, condStack)
+  of wElse: doElse(L, tok, config, condStack)
+  of wEnd: doEnd(L, tok, condStack)
   of wWrite:
     ppGetTok(L, tok)
-    msgs.msgWriteln(strtabs.`%`(tokToStr(tok), options.gConfigVars,
+    msgs.msgWriteln(config, strtabs.`%`(tokToStr(tok), config.configVars,
                                 {useEnvironment, useKey}))
     ppGetTok(L, tok)
   else:
@@ -144,55 +146,57 @@ proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef) =
       ppGetTok(L, tok)
       os.putEnv(key, os.getEnv(key) & tokToStr(tok))
       ppGetTok(L, tok)
-    else: lexMessage(L, errInvalidDirectiveX, tokToStr(tok))
+    else:
+      lexMessage(L, errGenerated, "invalid directive: '$1'" % tokToStr(tok))
 
-proc confTok(L: var TLexer, tok: var TToken; config: ConfigRef) =
+proc confTok(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
   ppGetTok(L, tok)
   while tok.ident != nil and tok.ident.s == "@":
-    parseDirective(L, tok, config)    # else: give the token to the parser
+    parseDirective(L, tok, config, condStack)    # else: give the token to the parser
 
 proc checkSymbol(L: TLexer, tok: TToken) =
   if tok.tokType notin {tkSymbol..tkInt64Lit, tkStrLit..tkTripleStrLit}:
-    lexMessage(L, errIdentifierExpected, tokToStr(tok))
+    lexMessage(L, errGenerated, "expected identifier, but got: " & tokToStr(tok))
 
-proc parseAssignment(L: var TLexer, tok: var TToken; config: ConfigRef) =
+proc parseAssignment(L: var TLexer, tok: var TToken;
+                     config: ConfigRef; condStack: var seq[bool]) =
   if tok.ident.s == "-" or tok.ident.s == "--":
-    confTok(L, tok, config)           # skip unnecessary prefix
+    confTok(L, tok, config, condStack)           # skip unnecessary prefix
   var info = getLineInfo(L, tok) # save for later in case of an error
   checkSymbol(L, tok)
   var s = tokToStr(tok)
-  confTok(L, tok, config)             # skip symbol
+  confTok(L, tok, config, condStack)             # skip symbol
   var val = ""
   while tok.tokType == tkDot:
     add(s, '.')
-    confTok(L, tok, config)
+    confTok(L, tok, config, condStack)
     checkSymbol(L, tok)
     add(s, tokToStr(tok))
-    confTok(L, tok, config)
+    confTok(L, tok, config, condStack)
   if tok.tokType == tkBracketLe:
     # BUGFIX: val, not s!
     # BUGFIX: do not copy '['!
-    confTok(L, tok, config)
+    confTok(L, tok, config, condStack)
     checkSymbol(L, tok)
     add(val, tokToStr(tok))
-    confTok(L, tok, config)
-    if tok.tokType == tkBracketRi: confTok(L, tok, config)
-    else: lexMessage(L, errTokenExpected, "']'")
+    confTok(L, tok, config, condStack)
+    if tok.tokType == tkBracketRi: confTok(L, tok, config, condStack)
+    else: lexMessage(L, errGenerated, "expected closing ']'")
     add(val, ']')
   let percent = tok.ident != nil and tok.ident.s == "%="
   if tok.tokType in {tkColon, tkEquals} or percent:
     if len(val) > 0: add(val, ':')
-    confTok(L, tok, config)           # skip ':' or '=' or '%'
+    confTok(L, tok, config, condStack)           # skip ':' or '=' or '%'
     checkSymbol(L, tok)
     add(val, tokToStr(tok))
-    confTok(L, tok, config)           # skip symbol
+    confTok(L, tok, config, condStack)           # skip symbol
     while tok.ident != nil and tok.ident.s == "&":
-      confTok(L, tok, config)
+      confTok(L, tok, config, condStack)
       checkSymbol(L, tok)
       add(val, tokToStr(tok))
-      confTok(L, tok, config)
+      confTok(L, tok, config, condStack)
   if percent:
-    processSwitch(s, strtabs.`%`(val, options.gConfigVars,
+    processSwitch(s, strtabs.`%`(val, config.configVars,
                                 {useEnvironment, useEmpty}), passPP, info, config)
   else:
     processSwitch(s, val, passPP, info, config)
@@ -207,48 +211,49 @@ proc readConfigFile(filename: string; cache: IdentCache; config: ConfigRef) =
     initToken(tok)
     openLexer(L, filename, stream, cache, config)
     tok.tokType = tkEof       # to avoid a pointless warning
-    confTok(L, tok, config)           # read in the first token
-    while tok.tokType != tkEof: parseAssignment(L, tok, config)
-    if len(condStack) > 0: lexMessage(L, errTokenExpected, "@end")
+    var condStack: seq[bool] = @[]
+    confTok(L, tok, config, condStack)           # read in the first token
+    while tok.tokType != tkEof: parseAssignment(L, tok, config, condStack)
+    if len(condStack) > 0: lexMessage(L, errGenerated, "expected @end")
     closeLexer(L)
-    rawMessage(hintConf, filename)
+    rawMessage(config, hintConf, filename)
 
 proc getUserConfigPath(filename: string): string =
   result = joinPath(getConfigDir(), filename)
 
-proc getSystemConfigPath(filename: string): string =
+proc getSystemConfigPath(conf: ConfigRef; filename: string): string =
   # try standard configuration file (installation did not distribute files
   # the UNIX way)
-  let p = getPrefixDir()
+  let p = getPrefixDir(conf)
   result = joinPath([p, "config", filename])
   when defined(unix):
     if not existsFile(result): result = joinPath([p, "etc", filename])
     if not existsFile(result): result = "/etc/" & filename
 
-proc loadConfigs*(cfg: string; cache: IdentCache; config: ConfigRef = nil) =
-  setDefaultLibpath()
+proc loadConfigs*(cfg: string; cache: IdentCache; conf: ConfigRef) =
+  setDefaultLibpath(conf)
 
-  if optSkipConfigFile notin gGlobalOptions:
-    readConfigFile(getSystemConfigPath(cfg), cache, config)
+  if optSkipConfigFile notin conf.globalOptions:
+    readConfigFile(getSystemConfigPath(conf, cfg), cache, conf)
 
-  if optSkipUserConfigFile notin gGlobalOptions:
-    readConfigFile(getUserConfigPath(cfg), cache, config)
+  if optSkipUserConfigFile notin conf.globalOptions:
+    readConfigFile(getUserConfigPath(cfg), cache, conf)
 
-  var pd = if gProjectPath.len > 0: gProjectPath else: getCurrentDir()
-  if optSkipParentConfigFiles notin gGlobalOptions:
+  let pd = if conf.projectPath.len > 0: conf.projectPath else: getCurrentDir()
+  if optSkipParentConfigFiles notin conf.globalOptions:
     for dir in parentDirs(pd, fromRoot=true, inclusive=false):
-      readConfigFile(dir / cfg, cache, config)
+      readConfigFile(dir / cfg, cache, conf)
 
-  if optSkipProjConfigFile notin gGlobalOptions:
-    readConfigFile(pd / cfg, cache, config)
+  if optSkipProjConfigFile notin conf.globalOptions:
+    readConfigFile(pd / cfg, cache, conf)
 
-    if gProjectName.len != 0:
+    if conf.projectName.len != 0:
       # new project wide config file:
-      var projectConfig = changeFileExt(gProjectFull, "nimcfg")
+      var projectConfig = changeFileExt(conf.projectFull, "nimcfg")
       if not fileExists(projectConfig):
-        projectConfig = changeFileExt(gProjectFull, "nim.cfg")
-      readConfigFile(projectConfig, cache, config)
+        projectConfig = changeFileExt(conf.projectFull, "nim.cfg")
+      readConfigFile(projectConfig, cache, conf)
 
-proc loadConfigs*(cfg: string; config: ConfigRef = nil) =
+proc loadConfigs*(cfg: string; conf: ConfigRef) =
   # for backwards compatibility only.
-  loadConfigs(cfg, newIdentCache(), config)
+  loadConfigs(cfg, newIdentCache(), conf)
diff --git a/compiler/nimfix/nimfix.nim b/compiler/nimfix/nimfix.nim
index 2ef375b00..c3e29f9a1 100644
--- a/compiler/nimfix/nimfix.nim
+++ b/compiler/nimfix/nimfix.nim
@@ -38,7 +38,7 @@ In addition, all command line options of Nim are supported.
 proc mainCommand =
   registerPass verbosePass
   registerPass semPass
-  gCmd = cmdPretty
+  conf.cmd = cmdPretty
   searchPaths.add options.libpath
   if gProjectFull.len != 0:
     # current path is always looked first for modules
diff --git a/compiler/nimfix/pretty.nim b/compiler/nimfix/pretty.nim
index 7af2a86dc..96429ad53 100644
--- a/compiler/nimfix/pretty.nim
+++ b/compiler/nimfix/pretty.nim
@@ -13,7 +13,8 @@
 import
   strutils, os, intsets, strtabs
 
-import ".." / [options, ast, astalgo, msgs, semdata, ropes, idents]
+import ".." / [options, ast, astalgo, msgs, semdata, ropes, idents,
+  configuration]
 import prettybase
 
 type
@@ -24,11 +25,11 @@ var
   gStyleCheck*: StyleCheck
   gCheckExtern*, gOnlyMainfile*: bool
 
-proc overwriteFiles*() =
-  let doStrip = options.getConfigVar("pretty.strip").normalize == "on"
+proc overwriteFiles*(conf: ConfigRef) =
+  let doStrip = options.getConfigVar(conf, "pretty.strip").normalize == "on"
   for i in 0 .. high(gSourceFiles):
     if gSourceFiles[i].dirty and not gSourceFiles[i].isNimfixFile and
-        (not gOnlyMainfile or gSourceFiles[i].fileIdx == gProjectMainIdx.FileIndex):
+        (not gOnlyMainfile or gSourceFiles[i].fileIdx == conf.projectMainIdx.FileIndex):
       let newFile = if gOverWrite: gSourceFiles[i].fullpath
                     else: gSourceFiles[i].fullpath.changeFileExt(".pretty.nim")
       try:
@@ -41,7 +42,7 @@ proc overwriteFiles*() =
           f.write(gSourceFiles[i].newline)
         f.close
       except IOError:
-        rawMessage(errCannotOpenFile, newFile)
+        rawMessage(conf, errGenerated, "cannot open file: " & newFile)
 
 proc `=~`(s: string, a: openArray[string]): bool =
   for x in a:
@@ -110,25 +111,25 @@ proc replaceInFile(info: TLineInfo; newName: string) =
     system.shallowCopy(gSourceFiles[info.fileIndex.int].lines[info.line.int-1], x)
     gSourceFiles[info.fileIndex.int].dirty = true
 
-proc checkStyle(info: TLineInfo, s: string, k: TSymKind; sym: PSym) =
+proc checkStyle(conf: ConfigRef; info: TLineInfo, s: string, k: TSymKind; sym: PSym) =
   let beau = beautifyName(s, k)
   if s != beau:
     if gStyleCheck == StyleCheck.Auto:
       sym.name = getIdent(beau)
       replaceInFile(info, beau)
     else:
-      message(info, hintName, beau)
+      message(conf, info, hintName, beau)
 
-proc styleCheckDefImpl(info: TLineInfo; s: PSym; k: TSymKind) =
+proc styleCheckDefImpl(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) =
   # operators stay as they are:
   if k in {skResult, skTemp} or s.name.s[0] notin prettybase.Letters: return
   if k in {skType, skGenericParam} and sfAnon in s.flags: return
   if {sfImportc, sfExportc} * s.flags == {} or gCheckExtern:
-    checkStyle(info, s.name.s, k, s)
+    checkStyle(conf, info, s.name.s, k, s)
 
 template styleCheckDef*(info: TLineInfo; s: PSym; k: TSymKind) =
   when defined(nimfix):
-    if gStyleCheck != StyleCheck.None: styleCheckDefImpl(info, s, k)
+    if gStyleCheck != StyleCheck.None: styleCheckDefImpl(conf, info, s, k)
 
 template styleCheckDef*(info: TLineInfo; s: PSym) =
   styleCheckDef(info, s, s.kind)
@@ -151,4 +152,4 @@ proc styleCheckUseImpl(info: TLineInfo; s: PSym) =
 
 template styleCheckUse*(info: TLineInfo; s: PSym) =
   when defined(nimfix):
-    if gStyleCheck != StyleCheck.None: styleCheckUseImpl(info, s)
+    if gStyleCheck != StyleCheck.None: styleCheckUseImpl(conf, info, s)
diff --git a/compiler/nimsets.nim b/compiler/nimsets.nim
index 8ec4d3c0d..6cb675ed8 100644
--- a/compiler/nimsets.nim
+++ b/compiler/nimsets.nim
@@ -12,27 +12,10 @@
 import
   ast, astalgo, trees, nversion, msgs, platform, bitsets, types, renderer
 
-proc toBitSet*(s: PNode, b: var TBitSet)
-  # this function is used for case statement checking:
-proc overlap*(a, b: PNode): bool
-proc inSet*(s: PNode, elem: PNode): bool
-proc someInSet*(s: PNode, a, b: PNode): bool
-proc emptyRange*(a, b: PNode): bool
-proc setHasRange*(s: PNode): bool
-  # returns true if set contains a range (needed by the code generator)
-  # these are used for constant folding:
-proc unionSets*(a, b: PNode): PNode
-proc diffSets*(a, b: PNode): PNode
-proc intersectSets*(a, b: PNode): PNode
-proc symdiffSets*(a, b: PNode): PNode
-proc containsSets*(a, b: PNode): bool
-proc equalSets*(a, b: PNode): bool
-proc cardSet*(a: PNode): BiggestInt
-# implementation
-
-proc inSet(s: PNode, elem: PNode): bool =
+proc inSet*(s: PNode, elem: PNode): bool =
+  assert s.kind == nkCurly
   if s.kind != nkCurly:
-    internalError(s.info, "inSet")
+    #internalError(s.info, "inSet")
     return false
   for i in countup(0, sonsLen(s) - 1):
     if s.sons[i].kind == nkRange:
@@ -44,7 +27,7 @@ proc inSet(s: PNode, elem: PNode): bool =
         return true
   result = false
 
-proc overlap(a, b: PNode): bool =
+proc overlap*(a, b: PNode): bool =
   if a.kind == nkRange:
     if b.kind == nkRange:
       # X..Y and C..D overlap iff (X <= D and C <= Y)
@@ -58,10 +41,11 @@ proc overlap(a, b: PNode): bool =
     else:
       result = sameValue(a, b)
 
-proc someInSet(s: PNode, a, b: PNode): bool =
+proc someInSet*(s: PNode, a, b: PNode): bool =
   # checks if some element of a..b is in the set s
+  assert s.kind == nkCurly
   if s.kind != nkCurly:
-    internalError(s.info, "SomeInSet")
+    #internalError(s.info, "SomeInSet")
     return false
   for i in countup(0, sonsLen(s) - 1):
     if s.sons[i].kind == nkRange:
@@ -74,7 +58,7 @@ proc someInSet(s: PNode, a, b: PNode): bool =
         return true
   result = false
 
-proc toBitSet(s: PNode, b: var TBitSet) =
+proc toBitSet*(s: PNode, b: var TBitSet) =
   var first, j: BiggestInt
   first = firstOrd(s.typ.sons[0])
   bitSetInit(b, int(getSize(s.typ)))
@@ -87,7 +71,7 @@ proc toBitSet(s: PNode, b: var TBitSet) =
     else:
       bitSetIncl(b, getOrdValue(s.sons[i]) - first)
 
-proc toTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
+proc toTreeSet*(s: TBitSet, settype: PType, info: TLineInfo): PNode =
   var
     a, b, e, first: BiggestInt # a, b are interval borders
     elemType: PType
@@ -128,18 +112,18 @@ template nodeSetOp(a, b: PNode, op: untyped) {.dirty.} =
   op(x, y)
   result = toTreeSet(x, a.typ, a.info)
 
-proc unionSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetUnion)
-proc diffSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetDiff)
-proc intersectSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetIntersect)
-proc symdiffSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetSymDiff)
+proc unionSets*(a, b: PNode): PNode = nodeSetOp(a, b, bitSetUnion)
+proc diffSets*(a, b: PNode): PNode = nodeSetOp(a, b, bitSetDiff)
+proc intersectSets*(a, b: PNode): PNode = nodeSetOp(a, b, bitSetIntersect)
+proc symdiffSets*(a, b: PNode): PNode = nodeSetOp(a, b, bitSetSymDiff)
 
-proc containsSets(a, b: PNode): bool =
+proc containsSets*(a, b: PNode): bool =
   var x, y: TBitSet
   toBitSet(a, x)
   toBitSet(b, y)
   result = bitSetContains(x, y)
 
-proc equalSets(a, b: PNode): bool =
+proc equalSets*(a, b: PNode): bool =
   var x, y: TBitSet
   toBitSet(a, x)
   toBitSet(b, y)
@@ -156,20 +140,19 @@ proc deduplicate*(a: PNode): PNode =
   toBitSet(a, x)
   result = toTreeSet(x, a.typ, a.info)
 
-proc cardSet(a: PNode): BiggestInt =
+proc cardSet*(a: PNode): BiggestInt =
   var x: TBitSet
   toBitSet(a, x)
   result = bitSetCard(x)
 
-proc setHasRange(s: PNode): bool =
+proc setHasRange*(s: PNode): bool =
+  assert s.kind == nkCurly
   if s.kind != nkCurly:
-    internalError(s.info, "SetHasRange")
     return false
   for i in countup(0, sonsLen(s) - 1):
     if s.sons[i].kind == nkRange:
       return true
   result = false
 
-proc emptyRange(a, b: PNode): bool =
+proc emptyRange*(a, b: PNode): bool =
   result = not leValue(a, b)  # a > b iff not (a <= b)
-
diff --git a/compiler/nversion.nim b/compiler/nversion.nim
index 85265a7c0..caa818d79 100644
--- a/compiler/nversion.nim
+++ b/compiler/nversion.nim
@@ -15,3 +15,6 @@ const
   VersionAsString* = system.NimVersion
   RodFileVersion* = "1223"       # modify this if the rod-format changes!
 
+  NimCompilerApiVersion* = 1 ## Check for the existance of this before accessing it
+                             ## as older versions of the compiler API do not
+                             ## declare this.
diff --git a/compiler/options.nim b/compiler/options.nim
index 0ce2f95ce..8fe3cf054 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -8,7 +8,9 @@
 #
 
 import
-  os, strutils, strtabs, osproc, sets
+  os, strutils, strtabs, osproc, sets, configuration, platform
+
+from terminal import isatty
 
 const
   hasTinyCBackend* = defined(tinyc)
@@ -17,7 +19,6 @@ const
   hasFFI* = defined(useFFI)
   newScopeForIf* = true
   useCaas* = not defined(noCaas)
-  noTimeMachine* = defined(avoidTimeMachine) and defined(macosx)
   copyrightYear* = "2018"
 
 type                          # please make sure we have under 32 options
@@ -71,6 +72,11 @@ type                          # please make sure we have under 32 options
     optIdeTerse               # idetools: use terse descriptions
     optNoCppExceptions        # use C exception handling even with CPP
     optExcessiveStackTrace    # fully qualified module filenames
+    optWholeProject           # for 'doc2': output any dependency
+    optListFullPaths
+    optNoNimblePath
+    optDynlibOverrideAll
+    optUseNimNamespace
 
   TGlobalOptions* = set[TGlobalOption]
 
@@ -113,74 +119,177 @@ type
     notnil,
     oldIterTransf
 
+  SymbolFilesOption* = enum
+    disabledSf, enabledSf, writeOnlySf, readOnlySf, v2Sf
+
   ConfigRef* = ref object ## eventually all global configuration should be moved here
     linesCompiled*: int  # all lines that have been compiled
+    options*: TOptions
+    globalOptions*: TGlobalOptions
+    exitcode*: int8
+    cmd*: TCommands  # the command
+    selectedGC*: TGCMode       # the selected GC
+    verbosity*: int            # how verbose the compiler is
+    numberOfProcessors*: int   # number of processors
+    evalExpr*: string          # expression for idetools --eval
+    lastCmdTime*: float        # when caas is enabled, we measure each command
+    symbolFiles*: SymbolFilesOption
+
     cppDefines*: HashSet[string]
     headerFile*: string
     features*: set[Feature]
     arguments*: string ## the arguments to be passed to the program that
                        ## should be run
+    helpWritten*: bool
+    ideCmd*: IdeCmd
+    oldNewlines*: bool
+    enableNotes*: TNoteKinds
+    disableNotes*: TNoteKinds
+    foreignPackageNotes*: TNoteKinds
+    notes*: TNoteKinds
+    mainPackageNotes*: TNoteKinds
+    errorCounter*: int
+    hintCounter*: int
+    warnCounter*: int
+    errorMax*: int
+    configVars*: StringTableRef
+    symbols*: StringTableRef ## We need to use a StringTableRef here as defined
+                             ## symbols are always guaranteed to be style
+                             ## insensitive. Otherwise hell would break lose.
+    packageCache*: StringTableRef
+    searchPaths*: seq[string]
+    lazyPaths*: seq[string]
+    outFile*, prefixDir*, libpath*, nimcacheDir*: string
+    dllOverrides, moduleOverrides*: StringTableRef
+    projectName*: string # holds a name like 'nim'
+    projectPath*: string # holds a path like /home/alice/projects/nim/compiler/
+    projectFull*: string # projectPath/projectName
+    projectIsStdin*: bool # whether we're compiling from stdin
+    projectMainIdx*: int32 # the canonical path id of the main module
+    command*: string # the main command (e.g. cc, check, scan, etc)
+    commandArgs*: seq[string] # any arguments after the main command
+    keepComments*: bool # whether the parser needs to keep comments
+    implicitImports*: seq[string] # modules that are to be implicitly imported
+    implicitIncludes*: seq[string] # modules that are to be implicitly included
+    docSeeSrcUrl*: string # if empty, no seeSrc will be generated. \
+    # The string uses the formatting variables `path` and `line`.
 
 const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel}
 
-proc newConfigRef*(): ConfigRef =
-  result = ConfigRef(cppDefines: initSet[string](),
-    headerFile: "", features: {})
-
-proc cppDefine*(c: ConfigRef; define: string) =
-  c.cppDefines.incl define
-
-var
-  gIdeCmd*: IdeCmd
-  gOldNewlines*: bool
-
 const
   ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck,
     optOverflowCheck, optBoundsCheck, optAssert, optNaNCheck, optInfCheck,
     optMoveCheck}
 
-var
-  gOptions*: TOptions = {optObjCheck, optFieldCheck, optRangeCheck,
-                         optBoundsCheck, optOverflowCheck, optAssert, optWarns,
-                         optHints, optStackTrace, optLineTrace,
-                         optPatterns, optNilCheck, optMoveCheck}
-  gGlobalOptions*: TGlobalOptions = {optThreadAnalysis}
-  gExitcode*: int8
-  gCmd*: TCommands = cmdNone  # the command
-  gSelectedGC* = gcRefc       # the selected GC
-  searchPaths*: seq[string] = @[]
-  lazyPaths*: seq[string]   = @[]
-  outFile*: string = ""
-  docSeeSrcUrl*: string = ""  # if empty, no seeSrc will be generated. \
-  # The string uses the formatting variables `path` and `line`.
-  #headerFile*: string = ""
-  gVerbosity* = 1             # how verbose the compiler is
-  gNumberOfProcessors*: int   # number of processors
-  gWholeProject*: bool        # for 'doc2': output any dependency
-  gEvalExpr* = ""             # expression for idetools --eval
-  gLastCmdTime*: float        # when caas is enabled, we measure each command
-  gListFullPaths*: bool
-  gPreciseStack*: bool = false
-  gNoNimblePath* = false
-  gDynlibOverrideAll*: bool
-  useNimNamespace*: bool
+  DefaultOptions* = {optObjCheck, optFieldCheck, optRangeCheck,
+    optBoundsCheck, optOverflowCheck, optAssert, optWarns,
+    optHints, optStackTrace, optLineTrace,
+    optPatterns, optNilCheck, optMoveCheck}
+  DefaultGlobalOptions* = {optThreadAnalysis}
 
-type
-  SymbolFilesOption* = enum
-    disabledSf, enabledSf, writeOnlySf, readOnlySf, v2Sf
+template newPackageCache*(): untyped =
+  newStringTable(when FileSystemCaseSensitive:
+                   modeCaseInsensitive
+                 else:
+                   modeCaseSensitive)
 
-var gSymbolFiles*: SymbolFilesOption
+proc newConfigRef*(): ConfigRef =
+  result = ConfigRef(
+    selectedGC: gcRefc,
+    verbosity: 1,
+    options: DefaultOptions,
+    globalOptions: DefaultGlobalOptions,
+    evalExpr: "",
+    cppDefines: initSet[string](),
+    headerFile: "", features: {}, foreignPackageNotes: {hintProcessing, warnUnknownMagic,
+    hintQuitCalled, hintExecuting},
+    notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1],
+    configVars: newStringTable(modeStyleInsensitive),
+    symbols: newStringTable(modeStyleInsensitive),
+    packageCache: newPackageCache(),
+    searchPaths: @[],
+    lazyPaths: @[],
+    outFile: "", prefixDir: "", libpath: "", nimcacheDir: "",
+    dllOverrides: newStringTable(modeCaseInsensitive),
+    moduleOverrides: newStringTable(modeStyleInsensitive),
+    projectName: "", # holds a name like 'nim'
+    projectPath: "", # holds a path like /home/alice/projects/nim/compiler/
+    projectFull: "", # projectPath/projectName
+    projectIsStdin: false, # whether we're compiling from stdin
+    projectMainIdx: 0'i32, # the canonical path id of the main module
+    command: "", # the main command (e.g. cc, check, scan, etc)
+    commandArgs: @[], # any arguments after the main command
+    keepComments: true, # whether the parser needs to keep comments
+    implicitImports: @[], # modules that are to be implicitly imported
+    implicitIncludes: @[], # modules that are to be implicitly included
+    docSeeSrcUrl: ""
+  )
+  # enable colors by default on terminals
+  if terminal.isatty(stderr):
+    incl(result.globalOptions, optUseColors)
+
+proc newPartialConfigRef*(): ConfigRef =
+  ## create a new ConfigRef that is only good enough for error reporting.
+  result = ConfigRef(
+    selectedGC: gcRefc,
+    verbosity: 1,
+    options: DefaultOptions,
+    globalOptions: DefaultGlobalOptions,
+    foreignPackageNotes: {hintProcessing, warnUnknownMagic,
+    hintQuitCalled, hintExecuting},
+    notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1])
 
-proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools}
-proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc
-template preciseStack*(): bool = gPreciseStack
+proc cppDefine*(c: ConfigRef; define: string) =
+  c.cppDefines.incl define
 
-template compilationCachePresent*: untyped =
-  gSymbolFiles in {enabledSf, writeOnlySf}
+proc isDefined*(conf: ConfigRef; symbol: string): bool =
+  if conf.symbols.hasKey(symbol):
+    result = conf.symbols[symbol] != "false"
+  elif cmpIgnoreStyle(symbol, CPU[targetCPU].name) == 0:
+    result = true
+  elif cmpIgnoreStyle(symbol, platform.OS[targetOS].name) == 0:
+    result = true
+  else:
+    case symbol.normalize
+    of "x86": result = targetCPU == cpuI386
+    of "itanium": result = targetCPU == cpuIa64
+    of "x8664": result = targetCPU == cpuAmd64
+    of "posix", "unix":
+      result = targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos,
+                            osQnx, osAtari, osAix,
+                            osHaiku, osVxWorks, osSolaris, osNetbsd,
+                            osFreebsd, osOpenbsd, osDragonfly, osMacosx,
+                            osAndroid}
+    of "linux":
+      result = targetOS in {osLinux, osAndroid}
+    of "bsd":
+      result = targetOS in {osNetbsd, osFreebsd, osOpenbsd, osDragonfly}
+    of "emulatedthreadvars":
+      result = platform.OS[targetOS].props.contains(ospLacksThreadVars)
+    of "msdos": result = targetOS == osDos
+    of "mswindows", "win32": result = targetOS == osWindows
+    of "macintosh": result = targetOS in {osMacos, osMacosx}
+    of "sunos": result = targetOS == osSolaris
+    of "littleendian": result = CPU[targetCPU].endian == platform.littleEndian
+    of "bigendian": result = CPU[targetCPU].endian == platform.bigEndian
+    of "cpu8": result = CPU[targetCPU].bit == 8
+    of "cpu16": result = CPU[targetCPU].bit == 16
+    of "cpu32": result = CPU[targetCPU].bit == 32
+    of "cpu64": result = CPU[targetCPU].bit == 64
+    of "nimrawsetjmp":
+      result = targetOS in {osSolaris, osNetbsd, osFreebsd, osOpenbsd,
+                            osDragonfly, osMacosx}
+    else: discard
+
+proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in {cmdDoc, cmdIdeTools}
+proc usesNativeGC*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc
+
+template compilationCachePresent*(conf: ConfigRef): untyped =
+  conf.symbolFiles in {enabledSf, writeOnlySf}
 #  {optCaasEnabled, optSymbolFiles} * gGlobalOptions != {}
 
-template optPreserveOrigSource*: untyped =
-  optEmbedOrigSrc in gGlobalOptions
+template optPreserveOrigSource*(conf: ConfigRef): untyped =
+  optEmbedOrigSrc in conf.globalOptions
 
 const
   genSubDir* = "nimcache"
@@ -195,82 +304,62 @@ const
   DocConfig* = "nimdoc.cfg"
   DocTexConfig* = "nimdoc.tex.cfg"
 
-# additional configuration variables:
-var
-  gConfigVars* = newStringTable(modeStyleInsensitive)
-  gDllOverrides = newStringTable(modeCaseInsensitive)
-  gModuleOverrides* = newStringTable(modeStyleInsensitive)
-  gPrefixDir* = "" # Overrides the default prefix dir in getPrefixDir proc.
-  libpath* = ""
-  gProjectName* = "" # holds a name like 'nim'
-  gProjectPath* = "" # holds a path like /home/alice/projects/nim/compiler/
-  gProjectFull* = "" # projectPath/projectName
-  gProjectIsStdin* = false # whether we're compiling from stdin
-  gProjectMainIdx*: int32 # the canonical path id of the main module
-  nimcacheDir* = ""
-  command* = "" # the main command (e.g. cc, check, scan, etc)
-  commandArgs*: seq[string] = @[] # any arguments after the main command
-  gKeepComments*: bool = true # whether the parser needs to keep comments
-  implicitImports*: seq[string] = @[] # modules that are to be implicitly imported
-  implicitIncludes*: seq[string] = @[] # modules that are to be implicitly included
-
 const oKeepVariableNames* = true
 
-template compilingLib*: bool =
+template compilingLib*(conf: ConfigRef): bool =
   gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}
 
-proc mainCommandArg*: string =
+proc mainCommandArg*(conf: ConfigRef): string =
   ## This is intended for commands like check or parse
   ## which will work on the main project file unless
   ## explicitly given a specific file argument
-  if commandArgs.len > 0:
-    result = commandArgs[0]
+  if conf.commandArgs.len > 0:
+    result = conf.commandArgs[0]
   else:
-    result = gProjectName
+    result = conf.projectName
 
-proc existsConfigVar*(key: string): bool =
-  result = hasKey(gConfigVars, key)
+proc existsConfigVar*(conf: ConfigRef; key: string): bool =
+  result = hasKey(conf.configVars, key)
 
-proc getConfigVar*(key: string): string =
-  result = gConfigVars.getOrDefault key
+proc getConfigVar*(conf: ConfigRef; key: string): string =
+  result = conf.configVars.getOrDefault key
 
-proc setConfigVar*(key, val: string) =
-  gConfigVars[key] = val
+proc setConfigVar*(conf: ConfigRef; key, val: string) =
+  conf.configVars[key] = val
 
-proc getOutFile*(filename, ext: string): string =
-  if options.outFile != "": result = options.outFile
+proc getOutFile*(conf: ConfigRef; filename, ext: string): string =
+  if conf.outFile != "": result = conf.outFile
   else: result = changeFileExt(filename, ext)
 
-proc getPrefixDir*(): string =
+proc getPrefixDir*(conf: ConfigRef): string =
   ## Gets the prefix dir, usually the parent directory where the binary resides.
   ##
-  ## This is overridden by some tools (namely nimsuggest) via the ``gPrefixDir``
+  ## This is overridden by some tools (namely nimsuggest) via the ``conf.prefixDir``
   ## global.
-  if gPrefixDir != "": result = gPrefixDir
-  else:
-    result = splitPath(getAppDir()).head
+  if conf.prefixDir != "": result = conf.prefixDir
+  else: result = splitPath(getAppDir()).head
 
-proc setDefaultLibpath*() =
+proc setDefaultLibpath*(conf: ConfigRef) =
   # set default value (can be overwritten):
-  if libpath == "":
+  if conf.libpath == "":
     # choose default libpath:
-    var prefix = getPrefixDir()
+    var prefix = getPrefixDir(conf)
     when defined(posix):
-      if prefix == "/usr": libpath = "/usr/lib/nim"
-      elif prefix == "/usr/local": libpath = "/usr/local/lib/nim"
-      else: libpath = joinPath(prefix, "lib")
-    else: libpath = joinPath(prefix, "lib")
+      if prefix == "/usr": conf.libpath = "/usr/lib/nim"
+      elif prefix == "/usr/local": conf.libpath = "/usr/local/lib/nim"
+      else: conf.libpath = joinPath(prefix, "lib")
+    else: conf.libpath = joinPath(prefix, "lib")
 
     # Special rule to support other tools (nimble) which import the compiler
     # modules and make use of them.
     let realNimPath = findExe("nim")
     # Find out if $nim/../../lib/system.nim exists.
-    let parentNimLibPath = realNimPath.parentDir().parentDir() / "lib"
-    if not fileExists(libpath / "system.nim") and
+    let parentNimLibPath = realNimPath.parentDir.parentDir / "lib"
+    if not fileExists(conf.libpath / "system.nim") and
         fileExists(parentNimlibPath / "system.nim"):
-      libpath = parentNimLibPath
+      conf.libpath = parentNimLibPath
 
-proc canonicalizePath*(path: string): string =
+proc canonicalizePath*(conf: ConfigRef; path: string): string =
   # on Windows, 'expandFilename' calls getFullPathName which doesn't do
   # case corrections, so we have to use this convoluted way of retrieving
   # the true filename (see tests/modules and Nimble uses 'import Uri' instead
@@ -282,12 +371,12 @@ proc canonicalizePath*(path: string): string =
   else:
     result = path.expandFilename
 
-proc shortenDir*(dir: string): string =
+proc shortenDir*(conf: ConfigRef; dir: string): string =
   ## returns the interesting part of a dir
-  var prefix = gProjectPath & DirSep
+  var prefix = conf.projectPath & DirSep
   if startsWith(dir, prefix):
     return substr(dir, len(prefix))
-  prefix = getPrefixDir() & DirSep
+  prefix = getPrefixDir(conf) & DirSep
   if startsWith(dir, prefix):
     return substr(dir, len(prefix))
   result = dir
@@ -298,114 +387,89 @@ proc removeTrailingDirSep*(path: string): string =
   else:
     result = path
 
-proc disableNimblePath*() =
-  gNoNimblePath = true
-  lazyPaths.setLen(0)
+proc disableNimblePath*(conf: ConfigRef) =
+  incl conf.globalOptions, optNoNimblePath
+  conf.lazyPaths.setLen(0)
 
 include packagehandling
 
-proc getNimcacheDir*: string =
-  result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir /
-                                                         genSubDir
-
+proc getNimcacheDir*(conf: ConfigRef): string =
+  result = if conf.nimcacheDir.len > 0: conf.nimcacheDir
+           else: shortenDir(conf, conf.projectPath) / genSubDir
 
-proc pathSubs*(p, config: string): string =
+proc pathSubs*(conf: ConfigRef; p, config: string): string =
   let home = removeTrailingDirSep(os.getHomeDir())
   result = unixToNativePath(p % [
-    "nim", getPrefixDir(),
-    "lib", libpath,
+    "nim", getPrefixDir(conf),
+    "lib", conf.libpath,
     "home", home,
     "config", config,
-    "projectname", options.gProjectName,
-    "projectpath", options.gProjectPath,
-    "projectdir", options.gProjectPath,
-    "nimcache", getNimcacheDir()])
+    "projectname", conf.projectName,
+    "projectpath", conf.projectPath,
+    "projectdir", conf.projectPath,
+    "nimcache", getNimcacheDir(conf)])
   if "~/" in result:
     result = result.replace("~/", home & '/')
 
-proc toGeneratedFile*(path, ext: string): string =
+proc toGeneratedFile*(conf: ConfigRef; path, ext: string): string =
   ## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"
   var (head, tail) = splitPath(path)
   #if len(head) > 0: head = shortenDir(head & dirSep)
-  result = joinPath([getNimcacheDir(), changeFileExt(tail, ext)])
+  result = joinPath([getNimcacheDir(conf), changeFileExt(tail, ext)])
   #echo "toGeneratedFile(", path, ", ", ext, ") = ", result
 
-when noTimeMachine:
-  var alreadyExcludedDirs = initSet[string]()
-  proc excludeDirFromTimeMachine(dir: string) {.raises: [].} =
-    ## Calls a macosx command on the directory to exclude it from backups.
-    ##
-    ## The macosx tmutil command is invoked to mark the specified path as an
-    ## item to be excluded from time machine backups. If a path already exists
-    ## with files before excluding it, newer files won't be added to the
-    ## directory, but previous files won't be removed from the backup until the
-    ## user deletes that directory.
-    ##
-    ## The whole proc is optional and will ignore all kinds of errors. The only
-    ## way to be sure that it works is to call ``tmutil isexcluded path``.
-    if alreadyExcludedDirs.contains(dir): return
-    alreadyExcludedDirs.incl(dir)
-    try:
-      var p = startProcess("/usr/bin/tmutil", args = ["addexclusion", dir])
-      discard p.waitForExit
-      p.close
-    except Exception:
-      discard
-
-proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
+proc completeGeneratedFilePath*(conf: ConfigRef; f: string, createSubDir: bool = true): string =
   var (head, tail) = splitPath(f)
   #if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep))
-  var subdir = getNimcacheDir() # / head
+  var subdir = getNimcacheDir(conf) # / head
   if createSubDir:
     try:
       createDir(subdir)
-      when noTimeMachine:
-        excludeDirFromTimeMachine(subdir)
     except OSError:
       writeLine(stdout, "cannot create directory: " & subdir)
       quit(1)
   result = joinPath(subdir, tail)
   #echo "completeGeneratedFilePath(", f, ") = ", result
 
-proc rawFindFile(f: string): string =
-  for it in searchPaths:
+proc rawFindFile(conf: ConfigRef; f: string): string =
+  for it in conf.searchPaths:
     result = joinPath(it, f)
     if existsFile(result):
-      return result.canonicalizePath
+      return canonicalizePath(conf, result)
   result = ""
 
-proc rawFindFile2(f: string): string =
-  for i, it in lazyPaths:
+proc rawFindFile2(conf: ConfigRef; f: string): string =
+  for i, it in conf.lazyPaths:
     result = joinPath(it, f)
     if existsFile(result):
       # bring to front
       for j in countDown(i,1):
-        swap(lazyPaths[j], lazyPaths[j-1])
+        swap(conf.lazyPaths[j], conf.lazyPaths[j-1])
 
-      return result.canonicalizePath
+      return canonicalizePath(conf, result)
   result = ""
 
-template patchModule() {.dirty.} =
-  if result.len > 0 and gModuleOverrides.len > 0:
-    let key = getPackageName(result) & "_" & splitFile(result).name
-    if gModuleOverrides.hasKey(key):
-      let ov = gModuleOverrides[key]
+template patchModule(conf: ConfigRef) {.dirty.} =
+  if result.len > 0 and conf.moduleOverrides.len > 0:
+    let key = getPackageName(conf, result) & "_" & splitFile(result).name
+    if conf.moduleOverrides.hasKey(key):
+      let ov = conf.moduleOverrides[key]
       if ov.len > 0: result = ov
 
-proc findFile*(f: string): string {.procvar.} =
+proc findFile*(conf: ConfigRef; f: string): string {.procvar.} =
   if f.isAbsolute:
     result = if f.existsFile: f else: ""
   else:
-    result = f.rawFindFile
+    result = rawFindFile(conf, f)
     if result.len == 0:
-      result = f.toLowerAscii.rawFindFile
+      result = rawFindFile(conf, f.toLowerAscii)
       if result.len == 0:
-        result = f.rawFindFile2
+        result = rawFindFile2(conf, f)
         if result.len == 0:
-          result = f.toLowerAscii.rawFindFile2
-  patchModule()
+          result = rawFindFile2(conf, f.toLowerAscii)
+  patchModule(conf)
 
-proc findModule*(modulename, currentModule: string): string =
+proc findModule*(conf: ConfigRef; modulename, currentModule: string): string =
   # returns path to module
   when defined(nimfix):
     # '.nimfix' modules are preferred over '.nim' modules so that specialized
@@ -415,16 +479,16 @@ proc findModule*(modulename, currentModule: string): string =
       let currentPath = currentModule.splitFile.dir
       result = currentPath / m
       if not existsFile(result):
-        result = findFile(m)
+        result = findFile(conf, m)
         if existsFile(result): return result
   let m = addFileExt(modulename, NimExt)
   let currentPath = currentModule.splitFile.dir
   result = currentPath / m
   if not existsFile(result):
-    result = findFile(m)
-  patchModule()
+    result = findFile(conf, m)
+  patchModule(conf)
 
-proc findProjectNimFile*(pkg: string): string =
+proc findProjectNimFile*(conf: ConfigRef; pkg: string): string =
   const extensions = [".nims", ".cfg", ".nimcfg", ".nimble"]
   var candidates: seq[string] = @[]
   for k, f in os.walkDir(pkg, relative=true):
@@ -449,11 +513,12 @@ proc canonDynlibName(s: string): string =
   else:
     result = s.substr(start)
 
-proc inclDynlibOverride*(lib: string) =
-  gDllOverrides[lib.canonDynlibName] = "true"
+proc inclDynlibOverride*(conf: ConfigRef; lib: string) =
+  conf.dllOverrides[lib.canonDynlibName] = "true"
 
-proc isDynlibOverride*(lib: string): bool =
-  result = gDynlibOverrideAll or gDllOverrides.hasKey(lib.canonDynlibName)
+proc isDynlibOverride*(conf: ConfigRef; lib: string): bool =
+  result = optDynlibOverrideAll in conf.globalOptions or
+     conf.dllOverrides.hasKey(lib.canonDynlibName)
 
 proc binaryStrSearch*(x: openArray[string], y: string): int =
   var a = 0
diff --git a/compiler/packagehandling.nim b/compiler/packagehandling.nim
index 758411e39..2efab58b0 100644
--- a/compiler/packagehandling.nim
+++ b/compiler/packagehandling.nim
@@ -15,23 +15,16 @@ iterator myParentDirs(p: string): string =
     if current.len == 0: break
     yield current
 
-template newPackageCache(): untyped =
-  newStringTable(when FileSystemCaseSensitive:
-                   modeCaseInsensitive
-                 else:
-                   modeCaseSensitive)
+proc resetPackageCache*(conf: ConfigRef) =
+  conf.packageCache = newPackageCache()
 
-var packageCache = newPackageCache()
-
-proc resetPackageCache*() = packageCache = newPackageCache()
-
-proc getPackageName*(path: string): string =
+proc getPackageName*(conf: ConfigRef; path: string): string =
   var parents = 0
   block packageSearch:
     for d in myParentDirs(path):
-      if packageCache.hasKey(d):
+      if conf.packageCache.hasKey(d):
         #echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name
-        return packageCache[d]
+        return conf.packageCache[d]
       inc parents
       for file in walkFiles(d / "*.nimble"):
         result = file.splitFile.name
@@ -43,12 +36,12 @@ proc getPackageName*(path: string): string =
   if result.isNil: result = ""
   for d in myParentDirs(path):
     #echo "set cache ", d, " |", result, "|", parents
-    packageCache[d] = result
+    conf.packageCache[d] = result
     dec parents
     if parents <= 0: break
 
-proc withPackageName*(path: string): string =
-  let x = path.getPackageName
+proc withPackageName*(conf: ConfigRef; path: string): string =
+  let x = getPackageName(conf, path)
   if x.len == 0:
     result = path
   else:
diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim
index 02c48c16d..944aec048 100644
--- a/compiler/parampatterns.nim
+++ b/compiler/parampatterns.nim
@@ -10,7 +10,8 @@
 ## This module implements the pattern matching features for term rewriting
 ## macro support.
 
-import strutils, ast, astalgo, types, msgs, idents, renderer, wordrecg, trees
+import strutils, ast, astalgo, types, msgs, idents, renderer, wordrecg, trees,
+  options
 
 # we precompile the pattern here for efficiency into some internal
 # stack based VM :-) Why? Because it's fun; I did no benchmarks to see if that
@@ -41,8 +42,8 @@ type
 const
   MaxStackSize* = 64 ## max required stack size by the VM
 
-proc patternError(n: PNode) =
-  localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
+proc patternError(n: PNode; conf: ConfigRef) =
+  localError(conf, n.info, "illformed AST: " & renderTree(n, {renderNoComments}))
 
 proc add(code: var TPatternCode, op: TOpcode) {.inline.} =
   add(code, chr(ord(op)))
@@ -53,42 +54,42 @@ proc whichAlias*(p: PSym): TAliasRequest =
   else:
     result = aqNone
 
-proc compileConstraints(p: PNode, result: var TPatternCode) =
+proc compileConstraints(p: PNode, result: var TPatternCode; conf: ConfigRef) =
   case p.kind
   of nkCallKinds:
     if p.sons[0].kind != nkIdent:
-      patternError(p.sons[0])
+      patternError(p.sons[0], conf)
       return
     let op = p.sons[0].ident
     if p.len == 3:
       if op.s == "|" or op.id == ord(wOr):
-        compileConstraints(p.sons[1], result)
-        compileConstraints(p.sons[2], result)
+        compileConstraints(p.sons[1], result, conf)
+        compileConstraints(p.sons[2], result, conf)
         result.add(ppOr)
       elif op.s == "&" or op.id == ord(wAnd):
-        compileConstraints(p.sons[1], result)
-        compileConstraints(p.sons[2], result)
+        compileConstraints(p.sons[1], result, conf)
+        compileConstraints(p.sons[2], result, conf)
         result.add(ppAnd)
       else:
-        patternError(p)
+        patternError(p, conf)
     elif p.len == 2 and (op.s == "~" or op.id == ord(wNot)):
-      compileConstraints(p.sons[1], result)
+      compileConstraints(p.sons[1], result, conf)
       result.add(ppNot)
     else:
-      patternError(p)
+      patternError(p, conf)
   of nkAccQuoted, nkPar:
     if p.len == 1:
-      compileConstraints(p.sons[0], result)
+      compileConstraints(p.sons[0], result, conf)
     else:
-      patternError(p)
+      patternError(p, conf)
   of nkIdent:
     let spec = p.ident.s.normalize
     case spec
-    of "atom":  result.add(ppAtom)
-    of "lit":   result.add(ppLit)
-    of "sym":   result.add(ppSym)
+    of "atom": result.add(ppAtom)
+    of "lit": result.add(ppLit)
+    of "sym": result.add(ppSym)
     of "ident": result.add(ppIdent)
-    of "call":  result.add(ppCall)
+    of "call": result.add(ppCall)
     of "alias": result[0] = chr(aqShouldAlias.ord)
     of "noalias": result[0] = chr(aqNoAlias.ord)
     of "lvalue": result.add(ppLValue)
@@ -97,24 +98,24 @@ proc compileConstraints(p: PNode, result: var TPatternCode) =
     of "nosideeffect": result.add(ppNoSideEffect)
     else:
       # check all symkinds:
-      internalAssert int(high(TSymKind)) < 255
+      internalAssert conf, int(high(TSymKind)) < 255
       for i in low(TSymKind)..high(TSymKind):
         if cmpIgnoreStyle(($i).substr(2), spec) == 0:
           result.add(ppSymKind)
           result.add(chr(i.ord))
           return
       # check all nodekinds:
-      internalAssert int(high(TNodeKind)) < 255
+      internalAssert conf, int(high(TNodeKind)) < 255
       for i in low(TNodeKind)..high(TNodeKind):
         if cmpIgnoreStyle($i, spec) == 0:
           result.add(ppNodeKind)
           result.add(chr(i.ord))
           return
-      patternError(p)
+      patternError(p, conf)
   else:
-    patternError(p)
+    patternError(p, conf)
 
-proc semNodeKindConstraints*(p: PNode): PNode =
+proc semNodeKindConstraints*(p: PNode; conf: ConfigRef): PNode =
   ## does semantic checking for a node kind pattern and compiles it into an
   ## efficient internal format.
   assert p.kind == nkCurlyExpr
@@ -123,11 +124,11 @@ proc semNodeKindConstraints*(p: PNode): PNode =
   result.strVal.add(chr(aqNone.ord))
   if p.len >= 2:
     for i in 1..<p.len:
-      compileConstraints(p.sons[i], result.strVal)
+      compileConstraints(p.sons[i], result.strVal, conf)
     if result.strVal.len > MaxStackSize-1:
-      internalError(p.info, "parameter pattern too complex")
+      internalError(conf, p.info, "parameter pattern too complex")
   else:
-    patternError(p)
+    patternError(p, conf)
   result.strVal.add(ppEof)
 
 type
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 0a3815f13..fbc57ebb6 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -27,7 +27,7 @@ when isMainModule:
   outp.close
 
 import
-  llstream, lexer, idents, strutils, ast, astalgo, msgs, options
+  llstream, lexer, idents, strutils, ast, astalgo, msgs, options, configuration
 
 type
   TParser* = object            # A TParser object represents a file that
@@ -97,7 +97,7 @@ proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream,
 proc openParser*(p: var TParser, filename: string, inputStream: PLLStream,
                  cache: IdentCache; config: ConfigRef;
                  strongSpaces=false) =
-  openParser(p, filename.fileInfoIdx, inputStream, cache, config, strongSpaces)
+  openParser(p, fileInfoIdx(config, filename), inputStream, cache, config, strongSpaces)
 
 proc closeParser(p: var TParser) =
   ## Close a parser, freeing up its resources.
@@ -107,9 +107,13 @@ proc parMessage(p: TParser, msg: TMsgKind, arg = "") =
   ## Produce and emit the parser message `arg` to output.
   lexMessageTok(p.lex, msg, p.tok, arg)
 
-proc parMessage(p: TParser, msg: TMsgKind, tok: TToken) =
+proc parMessage(p: TParser, msg: string, tok: TToken) =
   ## Produce and emit a parser message to output about the token `tok`
-  parMessage(p, msg, prettyTok(tok))
+  parMessage(p, errGenerated, msg % prettyTok(tok))
+
+proc parMessage(p: TParser, arg: string) =
+  ## Produce and emit the parser message `arg` to output.
+  lexMessageTok(p.lex, errGenerated, p.tok, arg)
 
 template withInd(p, body: untyped) =
   let oldInd = p.currInd
@@ -142,6 +146,12 @@ proc skipComment(p: var TParser, node: PNode) =
 proc flexComment(p: var TParser, node: PNode) =
   if p.tok.indent < 0 or realInd(p): rawSkipComment(p, node)
 
+const
+  errInvalidIndentation = "invalid indentation"
+  errIdentifierExpected = "identifier expected, but got '$1'"
+  errExprExpected = "expression expected, but found '$1'"
+  errTokenExpected = "'$1' expected"
+
 proc skipInd(p: var TParser) =
   if p.tok.indent >= 0:
     if not realInd(p): parMessage(p, errInvalidIndentation)
@@ -160,11 +170,11 @@ proc getTokNoInd(p: var TParser) =
 
 proc expectIdentOrKeyw(p: TParser) =
   if p.tok.tokType != tkSymbol and not isKeyword(p.tok.tokType):
-    lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
+    lexMessage(p.lex, errGenerated, errIdentifierExpected % prettyTok(p.tok))
 
 proc expectIdent(p: TParser) =
   if p.tok.tokType != tkSymbol:
-    lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
+    lexMessage(p.lex, errGenerated, errIdentifierExpected % prettyTok(p.tok))
 
 proc eat(p: var TParser, tokType: TTokType) =
   ## Move the parser to the next token if the current token is of type
@@ -172,7 +182,8 @@ proc eat(p: var TParser, tokType: TTokType) =
   if p.tok.tokType == tokType:
     getTok(p)
   else:
-    lexMessageTok(p.lex, errTokenExpected, p.tok, TokTypeToStr[tokType])
+    lexMessage(p.lex, errGenerated,
+      "expected: '" & TokTypeToStr[tokType] & "', but got: '" & prettyTok(p.tok) & "'")
 
 proc parLineInfo(p: TParser): TLineInfo =
   ## Retrieve the line information associated with the parser's current state.
@@ -886,7 +897,7 @@ proc parsePragma(p: var TParser): PNode =
       skipComment(p, a)
   optPar(p)
   if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p)
-  else: parMessage(p, errTokenExpected, ".}")
+  else: parMessage(p, "expected '.}'")
   dec p.inPragma
 
 proc identVis(p: var TParser; allowDot=false): PNode =
@@ -947,7 +958,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
   else:
     addSon(result, newNodeP(nkEmpty, p))
     if p.tok.tokType != tkEquals and withBothOptional notin flags:
-      parMessage(p, errColonOrEqualsExpected, p.tok)
+      parMessage(p, "':' or '=' expected, but got '$1'", p.tok)
   if p.tok.tokType == tkEquals:
     getTok(p)
     optInd(p, result)
@@ -1020,7 +1031,7 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
         parMessage(p, errGenerated, "the syntax is 'parameter: var T', not 'var parameter: T'")
         break
       else:
-        parMessage(p, errTokenExpected, ")")
+        parMessage(p, "expected closing ')'")
         break
       addSon(result, a)
       if p.tok.tokType notin {tkComma, tkSemiColon}: break
@@ -1181,7 +1192,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
     if mode == pmTypeDef:
       result = parseTypeClass(p)
     else:
-      parMessage(p, errInvalidToken, p.tok)
+      parMessage(p, "the 'concept' keyword is only valid in 'type' sections")
   of tkStatic:
     let info = parLineInfo(p)
     getTokNoInd(p)
@@ -1291,7 +1302,7 @@ proc postExprBlocks(p: var TParser, x: PNode): PNode =
       if nextBlock.kind == nkElse: break
   else:
     if openingParams.kind != nkEmpty:
-      parMessage(p, errTokenExpected, ":")
+      parMessage(p, "expected ':'")
 
 proc parseExprStmt(p: var TParser): PNode =
   #| exprStmt = simpleExpr
@@ -1527,7 +1538,7 @@ proc parseTry(p: var TParser; isExpr: bool): PNode =
     addSon(b, parseStmt(p))
     addSon(result, b)
     if b.kind == nkFinally: break
-  if b == nil: parMessage(p, errTokenExpected, "except")
+  if b == nil: parMessage(p, "expected 'except'")
 
 proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode =
   #| exceptBlock = 'except' colcom stmt
@@ -1582,7 +1593,7 @@ proc parseAsm(p: var TParser): PNode =
   of tkTripleStrLit: addSon(result,
                             newStrNodeP(nkTripleStrLit, p.tok.literal, p))
   else:
-    parMessage(p, errStringLiteralExpected)
+    parMessage(p, "the 'asm' statement takes a string literal")
     addSon(result, ast.emptyNode)
     return
   getTok(p)
@@ -1761,7 +1772,7 @@ proc parseEnum(p: var TParser): PNode =
         p.tok.tokType == tkEof:
       break
   if result.len <= 1:
-    lexMessageTok(p.lex, errIdentifierExpected, p.tok, prettyTok(p.tok))
+    parMessage(p, errIdentifierExpected, p.tok)
 
 proc parseObjectPart(p: var TParser): PNode
 proc parseObjectWhen(p: var TParser): PNode =
@@ -2124,7 +2135,7 @@ proc parseStmt(p: var TParser): PNode =
     case p.tok.tokType
     of tkIf, tkWhile, tkCase, tkTry, tkFor, tkBlock, tkAsm, tkProc, tkFunc,
        tkIterator, tkMacro, tkType, tkConst, tkWhen, tkVar:
-      parMessage(p, errComplexStmtRequiresInd)
+      parMessage(p, "complex statement requires indentation")
       result = ast.emptyNode
     else:
       if p.inSemiStmtList > 0:
diff --git a/compiler/passaux.nim b/compiler/passaux.nim
index 2065d5893..568fb4c23 100644
--- a/compiler/passaux.nim
+++ b/compiler/passaux.nim
@@ -10,22 +10,26 @@
 ## implements some little helper passes
 
 import
-  strutils, ast, astalgo, passes, idents, msgs, options, idgen
+  strutils, ast, astalgo, passes, idents, msgs, options, idgen, configuration
 
 from modulegraphs import ModuleGraph
 
+type
+  VerboseRef = ref object of TPassContext
+    config: ConfigRef
+
 proc verboseOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext =
   #MessageOut('compiling ' + s.name.s);
-  result = nil                # we don't need a context
-  rawMessage(hintProcessing, s.name.s)
+  result = VerboseRef(config: graph.config)
+  rawMessage(graph.config, hintProcessing, s.name.s)
 
 proc verboseProcess(context: PPassContext, n: PNode): PNode =
   result = n
-  if context != nil: internalError("logpass: context is not nil")
-  if gVerbosity == 3:
+  let v = VerboseRef(context)
+  if v.config.verbosity == 3:
     # system.nim deactivates all hints, for verbosity:3 we want the processing
     # messages nonetheless, so we activate them again unconditionally:
-    incl(msgs.gNotes, hintProcessing)
-    message(n.info, hintProcessing, $idgen.gFrontendId)
+    incl(v.config.notes, hintProcessing)
+    message(v.config, n.info, hintProcessing, $idgen.gFrontendId)
 
 const verbosePass* = makePass(open = verboseOpen, process = verboseProcess)
diff --git a/compiler/passes.nim b/compiler/passes.nim
index b104cd132..8f9f57f3d 100644
--- a/compiler/passes.nim
+++ b/compiler/passes.nim
@@ -13,7 +13,8 @@
 import
   strutils, options, ast, astalgo, llstream, msgs, platform, os,
   condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
-  nimsets, syntaxes, times, rodread, idgen, modulegraphs, reorder, rod
+  nimsets, syntaxes, times, rodread, idgen, modulegraphs, reorder, rod,
+  configuration
 
 
 type
@@ -57,11 +58,11 @@ var
 
 # implementation
 
-proc skipCodegen*(n: PNode): bool {.inline.} =
+proc skipCodegen*(config: ConfigRef; n: PNode): bool {.inline.} =
   # can be used by codegen passes to determine whether they should do
   # something with `n`. Currently, this ignores `n` and uses the global
   # error count instead.
-  result = msgs.gErrorCounter > 0
+  result = config.errorCounter > 0
 
 const
   maxPasses = 10
@@ -139,20 +140,21 @@ proc closePassesCached(graph: ModuleGraph; a: var TPassContextArray) =
       m = gPasses[i].close(graph, a[i], m)
     a[i] = nil                # free the memory here
 
-proc resolveMod(module, relativeTo: string): FileIndex =
-  let fullPath = findModule(module, relativeTo)
+proc resolveMod(conf: ConfigRef; module, relativeTo: string): FileIndex =
+  let fullPath = findModule(conf, module, relativeTo)
   if fullPath.len == 0:
     result = InvalidFileIDX
   else:
-    result = fullPath.fileInfoIdx
+    result = fileInfoIdx(conf, fullPath)
 
-proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
+proc processImplicits(conf: ConfigRef; implicits: seq[string], nodeKind: TNodeKind,
                       a: var TPassContextArray; m: PSym) =
   # XXX fixme this should actually be relative to the config file!
+  let gCmdLineInfo = newLineInfo(FileIndex(0), 1, 1)
   let relativeTo = m.info.toFullPath
   for module in items(implicits):
     # implicit imports should not lead to a module importing itself
-    if m.position != resolveMod(module, relativeTo).int32:
+    if m.position != resolveMod(conf, module, relativeTo).int32:
       var importStmt = newNodeI(nodeKind, gCmdLineInfo)
       var str = newStrNode(nkStrLit, module)
       str.info = gCmdLineInfo
@@ -202,7 +204,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
       let filename = fileIdx.toFullPathConsiderDirty
       s = llStreamOpen(filename, fmRead)
       if s == nil:
-        rawMessage(errCannotOpenFile, filename)
+        rawMessage(graph.config, errCannotOpenFile, filename)
         return false
     else:
       s = stream
@@ -214,8 +216,8 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
         # modules to include between compilation runs? we'd need to track that
         # in ROD files. I think we should enable this feature only
         # for the interactive mode.
-        processImplicits implicitImports, nkImportStmt, a, module
-        processImplicits implicitIncludes, nkIncludeStmt, a, module
+        processImplicits graph.config, graph.config.implicitImports, nkImportStmt, a, module
+        processImplicits graph.config, graph.config.implicitIncludes, nkIncludeStmt, a, module
 
       while true:
         if graph.stopCompile(): break
diff --git a/compiler/patterns.nim b/compiler/patterns.nim
index 31b76743e..5409a4811 100644
--- a/compiler/patterns.nim
+++ b/compiler/patterns.nim
@@ -150,7 +150,7 @@ proc matches(c: PPatternContext, p, n: PNode): bool =
     of "*": result = matchNested(c, p, n, rpn=false)
     of "**": result = matchNested(c, p, n, rpn=true)
     of "~": result = not matches(c, p.sons[1], n)
-    else: internalError(p.info, "invalid pattern")
+    else: doAssert(false, "invalid pattern")
     # template {add(a, `&` * b)}(a: string{noalias}, b: varargs[string]) =
     #   add(a, b)
   elif p.kind == nkCurlyExpr:
@@ -289,7 +289,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
         # constraint not fulfilled:
         if not ok: return nil
 
-  markUsed(n.info, s, c.graph.usageSym)
+  markUsed(c.config, n.info, s, c.graph.usageSym)
   if ctx.subMatch:
     assert m.len == 3
     m.sons[1] = result
diff --git a/compiler/plugins/itersgen.nim b/compiler/plugins/itersgen.nim
index dbc47e11e..ebb65dd4a 100644
--- a/compiler/plugins/itersgen.nim
+++ b/compiler/plugins/itersgen.nim
@@ -17,21 +17,21 @@ proc iterToProcImpl(c: PContext, n: PNode): PNode =
   result = newNodeI(nkStmtList, n.info)
   let iter = n[1]
   if iter.kind != nkSym or iter.sym.kind != skIterator:
-    localError(iter.info, "first argument needs to be an iterator")
+    localError(c.config, iter.info, "first argument needs to be an iterator")
     return
   if n[2].typ.isNil:
-    localError(n[2].info, "second argument needs to be a type")
+    localError(c.config, n[2].info, "second argument needs to be a type")
     return
   if n[3].kind != nkIdent:
-    localError(n[3].info, "third argument needs to be an identifier")
+    localError(c.config, n[3].info, "third argument needs to be an identifier")
     return
 
   let t = n[2].typ.skipTypes({tyTypeDesc, tyGenericInst})
   if t.kind notin {tyRef, tyPtr} or t.lastSon.kind != tyObject:
-    localError(n[2].info,
+    localError(c.config, n[2].info,
         "type must be a non-generic ref|ptr to object with state field")
     return
-  let body = liftIterToProc(iter.sym, iter.sym.getBody, t)
+  let body = liftIterToProc(c.graph, iter.sym, iter.sym.getBody, t)
 
   let prc = newSym(skProc, n[3].ident, iter.sym.owner, iter.sym.info)
   prc.typ = copyType(iter.sym.typ, prc, false)
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 0b8bcd374..de98a5e42 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -12,7 +12,7 @@
 import
   os, platform, condsyms, ast, astalgo, idents, semdata, msgs, renderer,
   wordrecg, ropes, options, strutils, extccomp, math, magicsys, trees,
-  rodread, types, lookups
+  rodread, types, lookups, configuration
 
 const
   FirstCallConv* = wNimcall
@@ -84,8 +84,12 @@ proc getPragmaVal*(procAst: PNode; name: TSpecialWord): PNode =
 proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
 # implementation
 
-proc invalidPragma*(n: PNode) =
-  localError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments}))
+const
+  errStringLiteralExpected = "string literal expected"
+  errIntLiteralExpected = "integer literal expected"
+
+proc invalidPragma*(c: PContext; n: PNode) =
+  localError(c.config, n.info, "invalid pragma: " % renderTree(n, {renderNoComments}))
 
 proc pragmaAsm*(c: PContext, n: PNode): char =
   result = '\0'
@@ -96,12 +100,12 @@ proc pragmaAsm*(c: PContext, n: PNode): char =
         case whichKeyword(it.sons[0].ident)
         of wSubsChar:
           if it.sons[1].kind == nkCharLit: result = chr(int(it.sons[1].intVal))
-          else: invalidPragma(it)
-        else: invalidPragma(it)
+          else: invalidPragma(c, it)
+        else: invalidPragma(c, it)
       else:
-        invalidPragma(it)
+        invalidPragma(c, it)
 
-proc setExternName(s: PSym, extname: string, info: TLineInfo) =
+proc setExternName(c: PContext; s: PSym, extname: string, info: TLineInfo) =
   # special cases to improve performance:
   if extname == "$1":
     s.loc.r = rope(s.name.s)
@@ -111,73 +115,73 @@ proc setExternName(s: PSym, extname: string, info: TLineInfo) =
     try:
       s.loc.r = rope(extname % s.name.s)
     except ValueError:
-      localError(info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)")
-  if gCmd == cmdPretty and '$' notin extname:
+      localError(c.config, info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)")
+  if c.config.cmd == cmdPretty and '$' notin extname:
     # note that '{.importc.}' is transformed into '{.importc: "$1".}'
     s.loc.flags.incl(lfFullExternalName)
 
-proc makeExternImport(s: PSym, extname: string, info: TLineInfo) =
-  setExternName(s, extname, info)
+proc makeExternImport(c: PContext; s: PSym, extname: string, info: TLineInfo) =
+  setExternName(c, s, extname, info)
   incl(s.flags, sfImportc)
   excl(s.flags, sfForward)
 
-proc makeExternExport(s: PSym, extname: string, info: TLineInfo) =
-  setExternName(s, extname, info)
+proc makeExternExport(c: PContext; s: PSym, extname: string, info: TLineInfo) =
+  setExternName(c, s, extname, info)
   incl(s.flags, sfExportc)
 
-proc processImportCompilerProc(s: PSym, extname: string, info: TLineInfo) =
-  setExternName(s, extname, info)
+proc processImportCompilerProc(c: PContext; s: PSym, extname: string, info: TLineInfo) =
+  setExternName(c, s, extname, info)
   incl(s.flags, sfImportc)
   excl(s.flags, sfForward)
   incl(s.loc.flags, lfImportCompilerProc)
 
-proc processImportCpp(s: PSym, extname: string, info: TLineInfo) =
-  setExternName(s, extname, info)
+proc processImportCpp(c: PContext; s: PSym, extname: string, info: TLineInfo) =
+  setExternName(c, s, extname, info)
   incl(s.flags, sfImportc)
   incl(s.flags, sfInfixCall)
   excl(s.flags, sfForward)
-  if gCmd == cmdCompileToC:
+  if c.config.cmd == cmdCompileToC:
     let m = s.getModule()
     incl(m.flags, sfCompileToCpp)
   extccomp.gMixedMode = true
 
-proc processImportObjC(s: PSym, extname: string, info: TLineInfo) =
-  setExternName(s, extname, info)
+proc processImportObjC(c: PContext; s: PSym, extname: string, info: TLineInfo) =
+  setExternName(c, s, extname, info)
   incl(s.flags, sfImportc)
   incl(s.flags, sfNamedParamCall)
   excl(s.flags, sfForward)
   let m = s.getModule()
   incl(m.flags, sfCompileToObjC)
 
-proc newEmptyStrNode(n: PNode): PNode {.noinline.} =
-  result = newNodeIT(nkStrLit, n.info, getSysType(tyString))
+proc newEmptyStrNode(c: PContext; n: PNode): PNode {.noinline.} =
+  result = newNodeIT(nkStrLit, n.info, getSysType(c.graph, n.info, tyString))
   result.strVal = ""
 
 proc getStrLitNode(c: PContext, n: PNode): PNode =
   if n.kind notin nkPragmaCallKinds or n.len != 2:
-    localError(n.info, errStringLiteralExpected)
+    localError(c.config, n.info, errStringLiteralExpected)
     # error correction:
-    result = newEmptyStrNode(n)
+    result = newEmptyStrNode(c, n)
   else:
     n.sons[1] = c.semConstExpr(c, n.sons[1])
     case n.sons[1].kind
     of nkStrLit, nkRStrLit, nkTripleStrLit: result = n.sons[1]
     else:
-      localError(n.info, errStringLiteralExpected)
+      localError(c.config, n.info, errStringLiteralExpected)
       # error correction:
-      result = newEmptyStrNode(n)
+      result = newEmptyStrNode(c, n)
 
 proc expectStrLit(c: PContext, n: PNode): string =
   result = getStrLitNode(c, n).strVal
 
 proc expectIntLit(c: PContext, n: PNode): int =
   if n.kind notin nkPragmaCallKinds or n.len != 2:
-    localError(n.info, errIntLiteralExpected)
+    localError(c.config, n.info, errIntLiteralExpected)
   else:
     n.sons[1] = c.semConstExpr(c, n.sons[1])
     case n.sons[1].kind
     of nkIntLit..nkInt64Lit: result = int(n.sons[1].intVal)
-    else: localError(n.info, errIntLiteralExpected)
+    else: localError(c.config, n.info, errIntLiteralExpected)
 
 proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string =
   if n.kind in nkPragmaCallKinds: result = expectStrLit(c, n)
@@ -190,7 +194,7 @@ proc processMagic(c: PContext, n: PNode, s: PSym) =
   #if sfSystemModule notin c.module.flags:
   #  liMessage(n.info, errMagicOnlyInSystem)
   if n.kind notin nkPragmaCallKinds or n.len != 2:
-    localError(n.info, errStringLiteralExpected)
+    localError(c.config, n.info, errStringLiteralExpected)
     return
   var v: string
   if n.sons[1].kind == nkIdent: v = n.sons[1].ident.s
@@ -199,7 +203,7 @@ proc processMagic(c: PContext, n: PNode, s: PSym) =
     if substr($m, 1) == v:
       s.magic = m
       break
-  if s.magic == mNone: message(n.info, warnUnknownMagic, v)
+  if s.magic == mNone: message(c.config, n.info, warnUnknownMagic, v)
 
 proc wordToCallConv(sw: TSpecialWord): TCallingConvention =
   # this assumes that the order of special words and calling conventions is
@@ -211,11 +215,11 @@ proc isTurnedOn(c: PContext, n: PNode): bool =
     let x = c.semConstBoolExpr(c, n.sons[1])
     n.sons[1] = x
     if x.kind == nkIntLit: return x.intVal != 0
-  localError(n.info, errOnOrOffExpected)
+  localError(c.config, n.info, "'on' or 'off' expected")
 
 proc onOff(c: PContext, n: PNode, op: TOptions) =
-  if isTurnedOn(c, n): gOptions = gOptions + op
-  else: gOptions = gOptions - op
+  if isTurnedOn(c, n): c.config.options = c.config.options + op
+  else: c.config.options = c.config.options - op
 
 proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) =
   if isTurnedOn(c, n): incl(c.module.flags, flag)
@@ -227,9 +231,9 @@ proc processCallConv(c: PContext, n: PNode) =
     case sw
     of FirstCallConv..LastCallConv:
       c.optionStack[^1].defaultCC = wordToCallConv(sw)
-    else: localError(n.info, errCallConvExpected)
+    else: localError(c.config, n.info, "calling convention expected")
   else:
-    localError(n.info, errCallConvExpected)
+    localError(c.config, n.info, "calling convention expected")
 
 proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib =
   for it in c.libs:
@@ -240,13 +244,13 @@ proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib =
   result.path = path
   c.libs.add result
   if path.kind in {nkStrLit..nkTripleStrLit}:
-    result.isOverriden = options.isDynlibOverride(path.strVal)
+    result.isOverriden = options.isDynlibOverride(c.config, path.strVal)
 
 proc expectDynlibNode(c: PContext, n: PNode): PNode =
   if n.kind notin nkPragmaCallKinds or n.len != 2:
-    localError(n.info, errStringLiteralExpected)
+    localError(c.config, n.info, errStringLiteralExpected)
     # error correction:
-    result = newEmptyStrNode(n)
+    result = newEmptyStrNode(c, n)
   else:
     # For the OpenGL wrapper we support:
     # {.dynlib: myGetProcAddr(...).}
@@ -254,8 +258,8 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode =
     if result.kind == nkSym and result.sym.kind == skConst:
       result = result.sym.ast # look it up
     if result.typ == nil or result.typ.kind notin {tyPointer, tyString, tyProc}:
-      localError(n.info, errStringLiteralExpected)
-      result = newEmptyStrNode(n)
+      localError(c.config, n.info, errStringLiteralExpected)
+      result = newEmptyStrNode(c, n)
 
 proc processDynLib(c: PContext, n: PNode, sym: PSym) =
   if (sym == nil) or (sym.kind == skModule):
@@ -278,39 +282,37 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) =
       sym.typ.callConv = ccCDecl
 
 proc processNote(c: PContext, n: PNode) =
-  if (n.kind in nkPragmaCallKinds) and (sonsLen(n) == 2) and
-      (n.sons[0].kind == nkBracketExpr) and
-      (n.sons[0].sons.len == 2) and
-      (n.sons[0].sons[1].kind == nkIdent) and
-      (n.sons[0].sons[0].kind == nkIdent):
-      #and (n.sons[1].kind == nkIdent):
+  if n.kind in nkPragmaCallKinds and len(n) == 2 and
+      n[0].kind == nkBracketExpr and
+      n[0].len == 2 and
+      n[0][1].kind == nkIdent and n[0][0].kind == nkIdent:
     var nk: TNoteKind
-    case whichKeyword(n.sons[0].sons[0].ident)
+    case whichKeyword(n[0][0].ident)
     of wHint:
-      var x = findStr(msgs.HintsToStr, n.sons[0].sons[1].ident.s)
+      var x = findStr(HintsToStr, n[0][1].ident.s)
       if x >= 0: nk = TNoteKind(x + ord(hintMin))
-      else: invalidPragma(n); return
+      else: invalidPragma(c, n); return
     of wWarning:
-      var x = findStr(msgs.WarningsToStr, n.sons[0].sons[1].ident.s)
+      var x = findStr(WarningsToStr, n[0][1].ident.s)
       if x >= 0: nk = TNoteKind(x + ord(warnMin))
-      else: invalidPragma(n); return
+      else: invalidPragma(c, n); return
     else:
-      invalidPragma(n)
+      invalidPragma(c, n)
       return
 
-    let x = c.semConstBoolExpr(c, n.sons[1])
+    let x = c.semConstBoolExpr(c, n[1])
     n.sons[1] = x
-    if x.kind == nkIntLit and x.intVal != 0: incl(gNotes, nk)
-    else: excl(gNotes, nk)
+    if x.kind == nkIntLit and x.intVal != 0: incl(c.config.notes, nk)
+    else: excl(c.config.notes, nk)
   else:
-    invalidPragma(n)
+    invalidPragma(c, n)
 
 proc processOption(c: PContext, n: PNode): bool =
   if n.kind notin nkPragmaCallKinds or n.len != 2: result = true
   elif n.sons[0].kind == nkBracketExpr: processNote(c, n)
   elif n.sons[0].kind != nkIdent: result = true
   else:
-    var sw = whichKeyword(n.sons[0].ident)
+    let sw = whichKeyword(n.sons[0].ident)
     case sw
     of wChecks: onOff(c, n, ChecksOptions)
     of wObjChecks: onOff(c, n, {optObjCheck})
@@ -337,32 +339,32 @@ proc processOption(c: PContext, n: PNode): bool =
     of wDynlib: processDynLib(c, n, nil)
     of wOptimization:
       if n.sons[1].kind != nkIdent:
-        invalidPragma(n)
+        invalidPragma(c, n)
       else:
         case n.sons[1].ident.s.normalize
         of "speed":
-          incl(gOptions, optOptimizeSpeed)
-          excl(gOptions, optOptimizeSize)
+          incl(c.config.options, optOptimizeSpeed)
+          excl(c.config.options, optOptimizeSize)
         of "size":
-          excl(gOptions, optOptimizeSpeed)
-          incl(gOptions, optOptimizeSize)
+          excl(c.config.options, optOptimizeSpeed)
+          incl(c.config.options, optOptimizeSize)
         of "none":
-          excl(gOptions, optOptimizeSpeed)
-          excl(gOptions, optOptimizeSize)
-        else: localError(n.info, errNoneSpeedOrSizeExpected)
+          excl(c.config.options, optOptimizeSpeed)
+          excl(c.config.options, optOptimizeSize)
+        else: localError(c.config, n.info, "'none', 'speed' or 'size' expected")
     of wImplicitStatic: onOff(c, n, {optImplicitStatic})
     of wPatterns: onOff(c, n, {optPatterns})
     else: result = true
 
 proc processPush(c: PContext, n: PNode, start: int) =
   if n.sons[start-1].kind in nkPragmaCallKinds:
-    localError(n.info, errGenerated, "'push' can't have arguments")
-  var x = newOptionEntry()
+    localError(c.config, n.info, "'push' cannot have arguments")
+  var x = newOptionEntry(c.config)
   var y = c.optionStack[^1]
-  x.options = gOptions
+  x.options = c.config.options
   x.defaultCC = y.defaultCC
   x.dynlib = y.dynlib
-  x.notes = gNotes
+  x.notes = c.config.notes
   c.optionStack.add(x)
   for i in countup(start, sonsLen(n) - 1):
     if processOption(c, n.sons[i]):
@@ -370,29 +372,29 @@ proc processPush(c: PContext, n: PNode, start: int) =
       if x.otherPragmas.isNil:
         x.otherPragmas = newNodeI(nkPragma, n.info)
       x.otherPragmas.add n.sons[i]
-    #localError(n.info, errOptionExpected)
+    #localError(c.config, n.info, errOptionExpected)
 
 proc processPop(c: PContext, n: PNode) =
   if c.optionStack.len <= 1:
-    localError(n.info, errAtPopWithoutPush)
+    localError(c.config, n.info, "{.pop.} without a corresponding {.push.}")
   else:
-    gOptions = c.optionStack[^1].options
-    gNotes = c.optionStack[^1].notes
+    c.config.options = c.optionStack[^1].options
+    c.config.notes = c.optionStack[^1].notes
     c.optionStack.setLen(c.optionStack.len - 1)
 
 proc processDefine(c: PContext, n: PNode) =
-  if (n.kind in nkPragmaCallKinds and n.len == 2) and (n.sons[1].kind == nkIdent):
-    defineSymbol(n.sons[1].ident.s)
-    message(n.info, warnDeprecated, "define")
+  if (n.kind in nkPragmaCallKinds and n.len == 2) and (n[1].kind == nkIdent):
+    defineSymbol(c.config.symbols, n[1].ident.s)
+    message(c.config, n.info, warnDeprecated, "define")
   else:
-    invalidPragma(n)
+    invalidPragma(c, n)
 
 proc processUndef(c: PContext, n: PNode) =
-  if (n.kind in nkPragmaCallKinds and n.len == 2) and (n.sons[1].kind == nkIdent):
-    undefSymbol(n.sons[1].ident.s)
-    message(n.info, warnDeprecated, "undef")
+  if (n.kind in nkPragmaCallKinds and n.len == 2) and (n[1].kind == nkIdent):
+    undefSymbol(c.config.symbols, n[1].ident.s)
+    message(c.config, n.info, warnDeprecated, "undef")
   else:
-    invalidPragma(n)
+    invalidPragma(c, n)
 
 type
   TLinkFeature = enum
@@ -406,18 +408,18 @@ proc relativeFile(c: PContext; n: PNode; ext=""): string =
   if not fileExists(result):
     if isAbsolute(s): result = s
     else:
-      result = findFile(s)
+      result = findFile(c.config, s)
       if result.len == 0: result = s
 
 proc processCompile(c: PContext, n: PNode) =
 
   proc getStrLit(c: PContext, n: PNode; i: int): string =
-    n.sons[i] = c.semConstExpr(c, n.sons[i])
-    case n.sons[i].kind
+    n.sons[i] = c.semConstExpr(c, n[i])
+    case n[i].kind
     of nkStrLit, nkRStrLit, nkTripleStrLit:
-      shallowCopy(result, n.sons[i].strVal)
+      shallowCopy(result, n[i].strVal)
     else:
-      localError(n.info, errStringLiteralExpected)
+      localError(c.config, n.info, errStringLiteralExpected)
       result = ""
 
   let it = if n.kind in nkPragmaCallKinds and n.len == 2: n.sons[1] else: n
@@ -428,26 +430,27 @@ proc processCompile(c: PContext, n: PNode) =
     for f in os.walkFiles(found):
       let nameOnly = extractFilename(f)
       var cf = Cfile(cname: f,
-          obj: completeCFilePath(dest % nameOnly),
+          obj: completeCFilePath(c.config, dest % nameOnly),
           flags: {CfileFlag.External})
-      extccomp.addExternalFileToCompile(cf)
+      extccomp.addExternalFileToCompile(c.config, cf)
   else:
     let s = expectStrLit(c, n)
     var found = parentDir(n.info.toFullPath) / s
     if not fileExists(found):
       if isAbsolute(s): found = s
       else:
-        found = findFile(s)
+        found = findFile(c.config, s)
         if found.len == 0: found = s
-    extccomp.addExternalFileToCompile(found)
+    extccomp.addExternalFileToCompile(c.config, found)
 
 proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
   let found = relativeFile(c, n, CC[cCompiler].objExt)
   case feature
-  of linkNormal: extccomp.addExternalFileToLink(found)
+  of linkNormal: extccomp.addExternalFileToLink(c.config, found)
   of linkSys:
-    extccomp.addExternalFileToLink(libpath / completeCFilePath(found, false))
-  else: internalError(n.info, "processCommonLink")
+    extccomp.addExternalFileToLink(c.config,
+      c.config.libpath / completeCFilePath(c.config, found, false))
+  else: internalError(c.config, n.info, "processCommonLink")
 
 proc pragmaBreakpoint(c: PContext, n: PNode) =
   discard getOptionalStr(c, n, "")
@@ -456,7 +459,7 @@ proc pragmaWatchpoint(c: PContext, n: PNode) =
   if n.kind in nkPragmaCallKinds and n.len == 2:
     n.sons[1] = c.semExpr(c, n.sons[1])
   else:
-    invalidPragma(n)
+    invalidPragma(c, n)
 
 proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
   case n.sons[1].kind
@@ -464,7 +467,7 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
     result = newNode(if n.kind == nkAsmStmt: nkAsmStmt else: nkArgList, n.info)
     var str = n.sons[1].strVal
     if str == "":
-      localError(n.info, errEmptyAsm)
+      localError(con.config, n.info, "empty 'asm' statement")
       return
     # now parse the string literal and substitute symbols:
     var a = 0
@@ -490,12 +493,12 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
       if c < 0: break
       a = c + 1
   else:
-    illFormedAstLocal(n)
+    illFormedAstLocal(n, con.config)
     result = newNode(nkAsmStmt, n.info)
 
 proc pragmaEmit(c: PContext, n: PNode) =
   if n.kind notin nkPragmaCallKinds or n.len != 2:
-    localError(n.info, errStringLiteralExpected)
+    localError(c.config, n.info, errStringLiteralExpected)
   else:
     let n1 = n[1]
     if n1.kind == nkBracket:
@@ -509,20 +512,20 @@ proc pragmaEmit(c: PContext, n: PNode) =
       of nkStrLit, nkRStrLit, nkTripleStrLit:
         n.sons[1] = semAsmOrEmit(c, n, '`')
       else:
-        localError(n.info, errStringLiteralExpected)
+        localError(c.config, n.info, errStringLiteralExpected)
 
-proc noVal(n: PNode) =
-  if n.kind in nkPragmaCallKinds and n.len > 1: invalidPragma(n)
+proc noVal(c: PContext; n: PNode) =
+  if n.kind in nkPragmaCallKinds and n.len > 1: invalidPragma(c, n)
 
 proc pragmaUnroll(c: PContext, n: PNode) =
   if c.p.nestedLoopCounter <= 0:
-    invalidPragma(n)
+    invalidPragma(c, n)
   elif n.kind in nkPragmaCallKinds and n.len == 2:
     var unrollFactor = expectIntLit(c, n)
     if unrollFactor <% 32:
       n.sons[1] = newIntNode(nkIntLit, unrollFactor)
     else:
-      invalidPragma(n)
+      invalidPragma(c, n)
 
 proc pragmaLine(c: PContext, n: PNode) =
   if n.kind in nkPragmaCallKinds and n.len == 2:
@@ -535,26 +538,26 @@ proc pragmaLine(c: PContext, n: PNode) =
       if x.kind == nkExprColonExpr: x = x.sons[1]
       if y.kind == nkExprColonExpr: y = y.sons[1]
       if x.kind != nkStrLit:
-        localError(n.info, errStringLiteralExpected)
+        localError(c.config, n.info, errStringLiteralExpected)
       elif y.kind != nkIntLit:
-        localError(n.info, errIntLiteralExpected)
+        localError(c.config, n.info, errIntLiteralExpected)
       else:
         # XXX this produces weird paths which are not properly resolved:
-        n.info.fileIndex = msgs.fileInfoIdx(x.strVal)
+        n.info.fileIndex = msgs.fileInfoIdx(c.config, x.strVal)
         n.info.line = uint16(y.intVal)
     else:
-      localError(n.info, errXExpected, "tuple")
+      localError(c.config, n.info, "tuple expected")
   else:
     # sensible default:
     n.info = getInfoContext(-1)
 
 proc processPragma(c: PContext, n: PNode, i: int) =
   let it = n[i]
-  if it.kind notin nkPragmaCallKinds and it.len == 2: invalidPragma(n)
-  elif it[0].kind != nkIdent: invalidPragma(n)
-  elif it[1].kind != nkIdent: invalidPragma(n)
+  if it.kind notin nkPragmaCallKinds and it.len == 2: invalidPragma(c, n)
+  elif it[0].kind != nkIdent: invalidPragma(c, n)
+  elif it[1].kind != nkIdent: invalidPragma(c, n)
 
-  var userPragma = newSym(skTemplate, it[1].ident, nil, it.info)
+  var userPragma = newSym(skTemplate, it[1].ident, nil, it.info, c.config.options)
   userPragma.ast = newNode(nkPragma, n.info, n.sons[i+1..^1])
   strTableAdd(c.userPragmas, userPragma)
 
@@ -562,7 +565,7 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) =
   proc processExc(c: PContext, x: PNode) =
     var t = skipTypes(c.semTypeNode(c, x, nil), skipPtrs)
     if t.kind != tyObject:
-      localError(x.info, errGenerated, "invalid type for raises/tags list")
+      localError(c.config, x.info, errGenerated, "invalid type for raises/tags list")
     x.typ = t
 
   if n.kind in nkPragmaCallKinds and n.len == 2:
@@ -572,51 +575,51 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) =
     else:
       for e in items(it): processExc(c, e)
   else:
-    invalidPragma(n)
+    invalidPragma(c, n)
 
 proc pragmaLockStmt(c: PContext; it: PNode) =
   if it.kind notin nkPragmaCallKinds or it.len != 2:
-    invalidPragma(it)
+    invalidPragma(c, it)
   else:
     let n = it[1]
     if n.kind != nkBracket:
-      localError(n.info, errGenerated, "locks pragma takes a list of expressions")
+      localError(c.config, n.info, errGenerated, "locks pragma takes a list of expressions")
     else:
       for i in 0 ..< n.len:
         n.sons[i] = c.semExpr(c, n.sons[i])
 
 proc pragmaLocks(c: PContext, it: PNode): TLockLevel =
   if it.kind notin nkPragmaCallKinds or it.len != 2:
-    invalidPragma(it)
+    invalidPragma(c, it)
   else:
     case it[1].kind
     of nkStrLit, nkRStrLit, nkTripleStrLit:
       if it[1].strVal == "unknown":
         result = UnknownLockLevel
       else:
-        localError(it[1].info, "invalid string literal for locks pragma (only allowed string is \"unknown\")")
+        localError(c.config, it[1].info, "invalid string literal for locks pragma (only allowed string is \"unknown\")")
     else:
       let x = expectIntLit(c, it)
       if x < 0 or x > MaxLockLevel:
-        localError(it[1].info, "integer must be within 0.." & $MaxLockLevel)
+        localError(c.config, it[1].info, "integer must be within 0.." & $MaxLockLevel)
       else:
         result = TLockLevel(x)
 
-proc typeBorrow(sym: PSym, n: PNode) =
+proc typeBorrow(c: PContext; sym: PSym, n: PNode) =
   if n.kind in nkPragmaCallKinds and n.len == 2:
     let it = n.sons[1]
     if it.kind != nkAccQuoted:
-      localError(n.info, "a type can only borrow `.` for now")
+      localError(c.config, n.info, "a type can only borrow `.` for now")
   incl(sym.typ.flags, tfBorrowDot)
 
-proc markCompilerProc(s: PSym) =
+proc markCompilerProc(c: PContext; s: PSym) =
   # minor hack ahead: FlowVar is the only generic .compilerProc type which
   # should not have an external name set:
   if s.kind != skType or s.name.s != "FlowVar":
-    makeExternExport(s, "$1", s.info)
+    makeExternExport(c, s, "$1", s.info)
   incl(s.flags, sfCompilerProc)
   incl(s.flags, sfUsed)
-  registerCompilerProc(s)
+  registerCompilerProc(c.graph, s)
 
 proc deprecatedStmt(c: PContext; outerPragma: PNode) =
   let pragma = outerPragma[1]
@@ -625,24 +628,24 @@ proc deprecatedStmt(c: PContext; outerPragma: PNode) =
     c.module.constraint = getStrLitNode(c, outerPragma)
     return
   if pragma.kind != nkBracket:
-    localError(pragma.info, "list of key:value pairs expected"); return
+    localError(c.config, pragma.info, "list of key:value pairs expected"); return
   for n in pragma:
     if n.kind in nkPragmaCallKinds and n.len == 2:
       let dest = qualifiedLookUp(c, n[1], {checkUndeclared})
       if dest == nil or dest.kind in routineKinds:
-        localError(n.info, warnUser, "the .deprecated pragma is unreliable for routines")
-      let src = considerQuotedIdent(n[0])
-      let alias = newSym(skAlias, src, dest, n[0].info)
+        localError(c.config, n.info, warnUser, "the .deprecated pragma is unreliable for routines")
+      let src = considerQuotedIdent(c.config, n[0])
+      let alias = newSym(skAlias, src, dest, n[0].info, c.config.options)
       incl(alias.flags, sfExported)
-      if sfCompilerProc in dest.flags: markCompilerProc(alias)
+      if sfCompilerProc in dest.flags: markCompilerProc(c, alias)
       addInterfaceDecl(c, alias)
       n.sons[1] = newSymNode(dest)
     else:
-      localError(n.info, "key:value pair expected")
+      localError(c.config, n.info, "key:value pair expected")
 
 proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
   if it.kind notin nkPragmaCallKinds or it.len != 2:
-    invalidPragma(it); return
+    invalidPragma(c, it); return
   let n = it[1]
   if n.kind == nkSym:
     result = n.sym
@@ -654,7 +657,8 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
       # We return a dummy symbol; later passes over the type will repair it.
       # Generic instantiation needs to know about this too. But we're lazy
       # and perform the lookup on demand instead.
-      result = newSym(skUnknown, considerQuotedIdent(n), nil, n.info)
+      result = newSym(skUnknown, considerQuotedIdent(c.config, n), nil, n.info,
+        c.config.options)
   else:
     result = qualifiedLookUp(c, n, {checkUndeclared})
 
@@ -667,12 +671,12 @@ proc semCustomPragma(c: PContext, n: PNode): PNode =
   elif n.kind in nkPragmaCallKinds + {nkIdent}:
     result = n
   else:
-    invalidPragma(n)
+    invalidPragma(c, n)
     return n
 
   let r = c.semOverloadedCall(c, result, n, {skTemplate}, {})
   if r.isNil or sfCustomPragma notin r[0].sym.flags:
-    invalidPragma(n)
+    invalidPragma(c, n)
   else:
     result = r
     if n.kind == nkIdent:
@@ -682,7 +686,7 @@ proc semCustomPragma(c: PContext, n: PNode): PNode =
 
 proc processExperimental(c: PContext; n: PNode; s: PSym) =
   if not isTopLevel(c):
-    localError(n.info, "'experimental' pragma only valid as toplevel statement")
+    localError(c.config, n.info, "'experimental' pragma only valid as toplevel statement")
   if n.kind notin nkPragmaCallKinds or n.len != 2:
     c.features.incl oldExperimentalFeatures
   else:
@@ -692,9 +696,9 @@ proc processExperimental(c: PContext; n: PNode; s: PSym) =
       try:
         c.features.incl parseEnum[Feature](n[1].strVal)
       except ValueError:
-        localError(n[1].info, "unknown experimental feature")
+        localError(c.config, n[1].info, "unknown experimental feature")
     else:
-      localError(n.info, errStringLiteralExpected)
+      localError(c.config, n.info, errStringLiteralExpected)
 
 proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
                   validPragmas: TSpecialWords): bool =
@@ -706,13 +710,13 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
   elif key.kind notin nkIdentKinds:
     n.sons[i] = semCustomPragma(c, it)
     return
-  let ident = considerQuotedIdent(key)
+  let ident = considerQuotedIdent(c.config, key)
   var userPragma = strTableGet(c.userPragmas, ident)
   if userPragma != nil:
     # number of pragmas increase/decrease with user pragma expansion
     inc c.instCounter
     if c.instCounter > 100:
-      globalError(it.info, errRecursiveDependencyX, userPragma.name.s)
+      globalError(c.config, it.info, "recursive dependency: " & userPragma.name.s)
 
     pragma(c, sym, userPragma.ast, validPragmas)
     n.sons[i..i] = userPragma.ast.sons # expand user pragma with its content
@@ -723,78 +727,78 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
     if k in validPragmas:
       case k
       of wExportc:
-        makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info)
+        makeExternExport(c, sym, getOptionalStr(c, it, "$1"), it.info)
         incl(sym.flags, sfUsed) # avoid wrong hints
       of wImportc:
         let name = getOptionalStr(c, it, "$1")
-        cppDefine(c.graph.config, name)
-        makeExternImport(sym, name, it.info)
+        cppDefine(c.config, name)
+        makeExternImport(c, sym, name, it.info)
       of wImportCompilerProc:
         let name = getOptionalStr(c, it, "$1")
-        cppDefine(c.graph.config, name)
-        processImportCompilerProc(sym, name, it.info)
-      of wExtern: setExternName(sym, expectStrLit(c, it), it.info)
+        cppDefine(c.config, name)
+        processImportCompilerProc(c, sym, name, it.info)
+      of wExtern: setExternName(c, sym, expectStrLit(c, it), it.info)
       of wImmediate:
         if sym.kind in {skTemplate, skMacro}:
           incl(sym.flags, sfImmediate)
           incl(sym.flags, sfAllUntyped)
-          message(n.info, warnDeprecated, "use 'untyped' parameters instead; immediate")
-        else: invalidPragma(it)
+          message(c.config, n.info, warnDeprecated, "use 'untyped' parameters instead; immediate")
+        else: invalidPragma(c, it)
       of wDirty:
         if sym.kind == skTemplate: incl(sym.flags, sfDirty)
-        else: invalidPragma(it)
+        else: invalidPragma(c, it)
       of wImportCpp:
-        processImportCpp(sym, getOptionalStr(c, it, "$1"), it.info)
+        processImportCpp(c, sym, getOptionalStr(c, it, "$1"), it.info)
       of wImportObjC:
-        processImportObjC(sym, getOptionalStr(c, it, "$1"), it.info)
+        processImportObjC(c, sym, getOptionalStr(c, it, "$1"), it.info)
       of wAlign:
-        if sym.typ == nil: invalidPragma(it)
+        if sym.typ == nil: invalidPragma(c, it)
         var align = expectIntLit(c, it)
         if (not isPowerOfTwo(align) and align != 0) or align >% high(int16):
-          localError(it.info, errPowerOfTwoExpected)
+          localError(c.config, it.info, "power of two expected")
         else:
           sym.typ.align = align.int16
       of wSize:
-        if sym.typ == nil: invalidPragma(it)
+        if sym.typ == nil: invalidPragma(c, it)
         var size = expectIntLit(c, it)
         if not isPowerOfTwo(size) or size <= 0 or size > 8:
-          localError(it.info, errPowerOfTwoExpected)
+          localError(c.config, it.info, "power of two expected")
         else:
           sym.typ.size = size
       of wNodecl:
-        noVal(it)
+        noVal(c, it)
         incl(sym.loc.flags, lfNoDecl)
       of wPure, wAsmNoStackFrame:
-        noVal(it)
+        noVal(c, it)
         if sym != nil:
-          if k == wPure and sym.kind in routineKinds: invalidPragma(it)
+          if k == wPure and sym.kind in routineKinds: invalidPragma(c, it)
           else: incl(sym.flags, sfPure)
       of wVolatile:
-        noVal(it)
+        noVal(c, it)
         incl(sym.flags, sfVolatile)
       of wRegister:
-        noVal(it)
+        noVal(c, it)
         incl(sym.flags, sfRegister)
       of wThreadVar:
-        noVal(it)
+        noVal(c, it)
         incl(sym.flags, {sfThread, sfGlobal})
       of wDeadCodeElimUnused: discard  # deprecated, dead code elim always on
       of wNoForward: pragmaNoForward(c, it)
       of wReorder: pragmaNoForward(c, it, sfReorder)
       of wMagic: processMagic(c, it, sym)
       of wCompileTime:
-        noVal(it)
+        noVal(c, it)
         incl(sym.flags, sfCompileTime)
         incl(sym.loc.flags, lfNoDecl)
       of wGlobal:
-        noVal(it)
+        noVal(c, it)
         incl(sym.flags, sfGlobal)
         incl(sym.flags, sfPure)
       of wMerge:
         # only supported for backwards compat, doesn't do anything anymore
-        noVal(it)
+        noVal(c, it)
       of wConstructor:
-        noVal(it)
+        noVal(c, it)
         incl(sym.flags, sfConstructor)
       of wHeader:
         var lib = getLib(c, libHeader, getStrLitNode(c, it))
@@ -807,25 +811,26 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
       of wOverride:
         sym.flags.incl sfOverriden
       of wNosideeffect:
-        noVal(it)
+        noVal(c, it)
         incl(sym.flags, sfNoSideEffect)
         if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
       of wSideeffect:
-        noVal(it)
+        noVal(c, it)
         incl(sym.flags, sfSideEffect)
       of wNoreturn:
-        noVal(it)
+        noVal(c, it)
         incl(sym.flags, sfNoReturn)
         if sym.typ[0] != nil:
-          localError(sym.ast[paramsPos][0].info, errNoReturnWithReturnTypeNotAllowed)
+          localError(c.config, sym.ast[paramsPos][0].info,
+            ".noreturn with return type not allowed")
       of wDynlib:
         processDynLib(c, it, sym)
       of wCompilerProc, wCore:
-        noVal(it)           # compilerproc may not get a string!
+        noVal(c, it)           # compilerproc may not get a string!
         cppDefine(c.graph.config, sym.name.s)
-        if sfFromGeneric notin sym.flags: markCompilerProc(sym)
+        if sfFromGeneric notin sym.flags: markCompilerProc(c, sym)
       of wProcVar:
-        noVal(it)
+        noVal(c, it)
         incl(sym.flags, sfProcvar)
       of wExplain:
         sym.flags.incl sfExplain
@@ -837,74 +842,74 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
         elif sym != nil: incl(sym.flags, sfDeprecated)
         else: incl(c.module.flags, sfDeprecated)
       of wVarargs:
-        noVal(it)
-        if sym.typ == nil: invalidPragma(it)
+        noVal(c, it)
+        if sym.typ == nil: invalidPragma(c, it)
         else: incl(sym.typ.flags, tfVarargs)
       of wBorrow:
         if sym.kind == skType:
-          typeBorrow(sym, it)
+          typeBorrow(c, sym, it)
         else:
-          noVal(it)
+          noVal(c, it)
           incl(sym.flags, sfBorrow)
       of wFinal:
-        noVal(it)
-        if sym.typ == nil: invalidPragma(it)
+        noVal(c, it)
+        if sym.typ == nil: invalidPragma(c, it)
         else: incl(sym.typ.flags, tfFinal)
       of wInheritable:
-        noVal(it)
-        if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(it)
+        noVal(c, it)
+        if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(c, it)
         else: incl(sym.typ.flags, tfInheritable)
       of wPackage:
-        noVal(it)
-        if sym.typ == nil: invalidPragma(it)
+        noVal(c, it)
+        if sym.typ == nil: invalidPragma(c, it)
         else: incl(sym.flags, sfForward)
       of wAcyclic:
-        noVal(it)
-        if sym.typ == nil: invalidPragma(it)
+        noVal(c, it)
+        if sym.typ == nil: invalidPragma(c, it)
         else: incl(sym.typ.flags, tfAcyclic)
       of wShallow:
-        noVal(it)
-        if sym.typ == nil: invalidPragma(it)
+        noVal(c, it)
+        if sym.typ == nil: invalidPragma(c, it)
         else: incl(sym.typ.flags, tfShallow)
       of wThread:
-        noVal(it)
+        noVal(c, it)
         incl(sym.flags, sfThread)
         incl(sym.flags, sfProcvar)
         if sym.typ != nil:
           incl(sym.typ.flags, tfThread)
           if sym.typ.callConv == ccClosure: sym.typ.callConv = ccDefault
       of wGcSafe:
-        noVal(it)
+        noVal(c, it)
         if sym != nil:
           if sym.kind != skType: incl(sym.flags, sfThread)
           if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
-          else: invalidPragma(it)
+          else: invalidPragma(c, it)
         else:
           discard "no checking if used as a code block"
       of wPacked:
-        noVal(it)
-        if sym.typ == nil: invalidPragma(it)
+        noVal(c, it)
+        if sym.typ == nil: invalidPragma(c, it)
         else: incl(sym.typ.flags, tfPacked)
-      of wHint: message(it.info, hintUser, expectStrLit(c, it))
-      of wWarning: message(it.info, warnUser, expectStrLit(c, it))
+      of wHint: message(c.config, it.info, hintUser, expectStrLit(c, it))
+      of wWarning: message(c.config, it.info, warnUser, expectStrLit(c, it))
       of wError:
         if sym != nil and sym.isRoutine:
           # This is subtle but correct: the error *statement* is only
           # allowed for top level statements. Seems to be easier than
           # distinguishing properly between
           # ``proc p() {.error}`` and ``proc p() = {.error: "msg".}``
-          noVal(it)
+          noVal(c, it)
           incl(sym.flags, sfError)
         else:
-          localError(it.info, errUser, expectStrLit(c, it))
-      of wFatal: fatal(it.info, errUser, expectStrLit(c, it))
+          localError(c.config, it.info, errUser, expectStrLit(c, it))
+      of wFatal: fatal(c.config, it.info, errUser, expectStrLit(c, it))
       of wDefine: processDefine(c, it)
       of wUndef: processUndef(c, it)
       of wCompile: processCompile(c, it)
       of wLink: processCommonLink(c, it, linkNormal)
       of wLinksys: processCommonLink(c, it, linkSys)
-      of wPassl: extccomp.addLinkOption(expectStrLit(c, it))
-      of wPassc: extccomp.addCompileOption(expectStrLit(c, it))
+      of wPassl: extccomp.addLinkOption(c.config, expectStrLit(c, it))
+      of wPassc: extccomp.addCompileOption(c.config, expectStrLit(c, it))
       of wBreakpoint: pragmaBreakpoint(c, it)
       of wWatchPoint: pragmaWatchpoint(c, it)
       of wPush:
@@ -918,10 +923,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
           processPragma(c, n, i)
           result = true
       of wDiscardable:
-        noVal(it)
+        noVal(c, it)
         if sym != nil: incl(sym.flags, sfDiscardable)
       of wNoInit:
-        noVal(it)
+        noVal(c, it)
         if sym != nil: incl(sym.flags, sfNoInit)
       of wCodegenDecl: processCodegenDecl(c, it, sym)
       of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
@@ -932,106 +937,106 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
          wPatterns:
         if processOption(c, it):
           # calling conventions (boring...):
-          localError(it.info, errOptionExpected)
+          localError(c.config, it.info, "option expected")
       of FirstCallConv..LastCallConv:
         assert(sym != nil)
-        if sym.typ == nil: invalidPragma(it)
+        if sym.typ == nil: invalidPragma(c, it)
         else: sym.typ.callConv = wordToCallConv(k)
       of wEmit: pragmaEmit(c, it)
       of wUnroll: pragmaUnroll(c, it)
-      of wLinearScanEnd, wComputedGoto: noVal(it)
+      of wLinearScanEnd, wComputedGoto: noVal(c, it)
       of wEffects:
         # is later processed in effect analysis:
-        noVal(it)
+        noVal(c, it)
       of wIncompleteStruct:
-        noVal(it)
-        if sym.typ == nil: invalidPragma(it)
+        noVal(c, it)
+        if sym.typ == nil: invalidPragma(c, it)
         else: incl(sym.typ.flags, tfIncompleteStruct)
       of wUnchecked:
-        noVal(it)
-        if sym.typ == nil: invalidPragma(it)
+        noVal(c, it)
+        if sym.typ == nil: invalidPragma(c, it)
         else: incl(sym.typ.flags, tfUncheckedArray)
       of wUnion:
-        noVal(it)
-        if sym.typ == nil: invalidPragma(it)
+        noVal(c, it)
+        if sym.typ == nil: invalidPragma(c, it)
         else: incl(sym.typ.flags, tfUnion)
       of wRequiresInit:
-        noVal(it)
-        if sym.typ == nil: invalidPragma(it)
+        noVal(c, it)
+        if sym.typ == nil: invalidPragma(c, it)
         else: incl(sym.typ.flags, tfNeedsInit)
       of wByRef:
-        noVal(it)
+        noVal(c, it)
         if sym == nil or sym.typ == nil:
-          if processOption(c, it): localError(it.info, errOptionExpected)
+          if processOption(c, it): localError(c.config, it.info, "option expected")
         else:
           incl(sym.typ.flags, tfByRef)
       of wByCopy:
-        noVal(it)
-        if sym.kind != skType or sym.typ == nil: invalidPragma(it)
+        noVal(c, it)
+        if sym.kind != skType or sym.typ == nil: invalidPragma(c, it)
         else: incl(sym.typ.flags, tfByCopy)
       of wPartial:
-        noVal(it)
-        if sym.kind != skType or sym.typ == nil: invalidPragma(it)
+        noVal(c, it)
+        if sym.kind != skType or sym.typ == nil: invalidPragma(c, it)
         else:
           incl(sym.typ.flags, tfPartial)
       of wInject, wGensym:
         # We check for errors, but do nothing with these pragmas otherwise
         # as they are handled directly in 'evalTemplate'.
-        noVal(it)
-        if sym == nil: invalidPragma(it)
+        noVal(c, it)
+        if sym == nil: invalidPragma(c, it)
       of wLine: pragmaLine(c, it)
       of wRaises, wTags: pragmaRaisesOrTags(c, it)
       of wLocks:
         if sym == nil: pragmaLockStmt(c, it)
-        elif sym.typ == nil: invalidPragma(it)
+        elif sym.typ == nil: invalidPragma(c, it)
         else: sym.typ.lockLevel = pragmaLocks(c, it)
       of wBitsize:
         if sym == nil or sym.kind != skField:
-          invalidPragma(it)
+          invalidPragma(c, it)
         else:
           sym.bitsize = expectIntLit(c, it)
       of wGuard:
         if sym == nil or sym.kind notin {skVar, skLet, skField}:
-          invalidPragma(it)
+          invalidPragma(c, it)
         else:
           sym.guard = pragmaGuard(c, it, sym.kind)
       of wGoto:
         if sym == nil or sym.kind notin {skVar, skLet}:
-          invalidPragma(it)
+          invalidPragma(c, it)
         else:
           sym.flags.incl sfGoto
       of wExportNims:
-        if sym == nil: invalidPragma(it)
-        else: magicsys.registerNimScriptSymbol(sym)
+        if sym == nil: invalidPragma(c, it)
+        else: magicsys.registerNimScriptSymbol(c.graph, sym)
       of wInjectStmt:
         if it.kind notin nkPragmaCallKinds or it.len != 2:
-          localError(it.info, errExprExpected)
+          localError(c.config, it.info, "expression expected")
         else:
           it.sons[1] = c.semExpr(c, it.sons[1])
       of wExperimental:
         processExperimental(c, it, sym)
       of wThis:
         if it.kind in nkPragmaCallKinds and it.len == 2:
-          c.selfName = considerQuotedIdent(it[1])
+          c.selfName = considerQuotedIdent(c.config, it[1])
         elif it.kind == nkIdent or it.len == 1:
           c.selfName = getIdent("self")
         else:
-          localError(it.info, "'this' pragma is allowed to have zero or one arguments")
+          localError(c.config, it.info, "'this' pragma is allowed to have zero or one arguments")
       of wNoRewrite:
-        noVal(it)
+        noVal(c, it)
       of wBase:
-        noVal(it)
+        noVal(c, it)
         sym.flags.incl sfBase
       of wIntDefine:
         sym.magic = mIntDefine
       of wStrDefine:
         sym.magic = mStrDefine
       of wUsed:
-        noVal(it)
-        if sym == nil: invalidPragma(it)
+        noVal(c, it)
+        if sym == nil: invalidPragma(c, it)
         else: sym.flags.incl sfUsed
       of wLiftLocals: discard
-      else: invalidPragma(it)
+      else: invalidPragma(c, it)
     else:
       n.sons[i] = semCustomPragma(c, it)
 
@@ -1046,12 +1051,12 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
         var i = 0
         while i < o.len():
           if singlePragma(c, sym, o, i, validPragmas):
-            internalError(n.info, "implicitPragmas")
+            internalError(c.config, n.info, "implicitPragmas")
           inc i
         popInfoContext()
 
     if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
-      localError(n.info, errDynlibRequiresExportc)
+      localError(c.config, n.info, ".dynlib requires .exportc")
     var lib = c.optionStack[^1].dynlib
     if {lfDynamicLib, lfHeader} * sym.loc.flags == {} and
         sfImportc in sym.flags and lib != nil:
@@ -1063,7 +1068,7 @@ proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
   if n == nil or n.sons == nil:
     return false
 
-  for p in n.sons:
+  for p in n:
     var key = if p.kind in nkPragmaCallKinds and p.len > 1: p[0] else: p
     if key.kind == nkIdent and whichKeyword(key.ident) == pragma:
       return true
diff --git a/compiler/procfind.nim b/compiler/procfind.nim
index f7d86aaef..042947e72 100644
--- a/compiler/procfind.nim
+++ b/compiler/procfind.nim
@@ -14,14 +14,12 @@ import
   ast, astalgo, msgs, semdata, types, trees, strutils
 
 proc equalGenericParams(procA, procB: PNode): bool =
-  if sonsLen(procA) != sonsLen(procB): return
+  if sonsLen(procA) != sonsLen(procB): return false
   for i in countup(0, sonsLen(procA) - 1):
     if procA.sons[i].kind != nkSym:
-      internalError(procA.info, "equalGenericParams")
-      return
+      return false
     if procB.sons[i].kind != nkSym:
-      internalError(procB.info, "equalGenericParams")
-      return
+      return false
     let a = procA.sons[i].sym
     let b = procB.sons[i].sym
     if a.name.id != b.name.id or
@@ -57,7 +55,7 @@ proc searchForProcOld*(c: PContext, scope: PScope, fn: PSym): PSym =
         of paramsEqual:
           return
         of paramsIncompatible:
-          localError(fn.info, errNotOverloadable, fn.name.s)
+          localError(c.config, fn.info, "overloaded '$1' leads to ambiguous calls" % fn.name.s)
           return
         of paramsNotEqual:
           discard
@@ -76,10 +74,10 @@ proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
           let message = ("public implementation '$1' has non-public " &
                          "forward declaration in $2") %
                         [getProcHeader(result), $result.info]
-          localError(fn.info, errGenerated, message)
+          localError(c.config, fn.info, message)
         return
       of paramsIncompatible:
-        localError(fn.info, errNotOverloadable, fn.name.s)
+        localError(c.config, fn.info, "overloaded '$1' leads to ambiguous calls" % fn.name.s)
         return
       of paramsNotEqual:
         discard
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index 0c861bdb8..259d0211f 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -10,7 +10,7 @@
 # This module implements the renderer of the standard Nim representation.
 
 import
-  lexer, options, idents, strutils, ast, msgs
+  lexer, options, idents, strutils, ast, msgs, configuration
 
 type
   TRenderFlag* = enum
@@ -40,6 +40,7 @@ type
     when defined(nimpretty):
       pendingNewlineCount: int
     fid*: FileIndex
+    config*: ConfigRef
 
 # We render the source code in a two phases: The first
 # determines how long the subtree will likely be, the second
@@ -90,7 +91,7 @@ const
   MaxLineLen = 80
   LineCommentColumn = 30
 
-proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
+proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags; config: ConfigRef) =
   g.comStack = @[]
   g.tokens = @[]
   g.indent = 0
@@ -102,6 +103,7 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
   g.pendingNL = -1
   g.pendingWhitespace = -1
   g.inGenericParams = false
+  g.config = config
 
 proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
   var length = len(g.tokens)
@@ -377,7 +379,7 @@ proc atom(g: TSrcGen; n: PNode): string =
     if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s
     else: result = "[type node]"
   else:
-    internalError("rnimsyn.atom " & $n.kind)
+    internalError(g.config, "rnimsyn.atom " & $n.kind)
     result = ""
 
 proc lcomma(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int =
@@ -1432,11 +1434,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     gTypeClassTy(g, n)
   else:
     #nkNone, nkExplicitTypeListCall:
-    internalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
+    internalError(g.config, n.info, "rnimsyn.gsub(" & $n.kind & ')')
 
 proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string =
   var g: TSrcGen
-  initSrcGen(g, renderFlags)
+  initSrcGen(g, renderFlags, newPartialConfigRef())
   # do not indent the initial statement list so that
   # writeFile("file.nim", repr n)
   # produces working Nim code:
@@ -1454,7 +1456,7 @@ proc renderModule*(n: PNode, infile, outfile: string,
   var
     f: File
     g: TSrcGen
-  initSrcGen(g, renderFlags)
+  initSrcGen(g, renderFlags, newPartialConfigRef())
   g.fid = fid
   for i in countup(0, sonsLen(n) - 1):
     gsub(g, n.sons[i])
@@ -1464,16 +1466,14 @@ proc renderModule*(n: PNode, infile, outfile: string,
        nkCommentStmt: putNL(g)
     else: discard
   gcoms(g)
-  if optStdout in gGlobalOptions:
-    write(stdout, g.buf)
-  elif open(f, outfile, fmWrite):
+  if open(f, outfile, fmWrite):
     write(f, g.buf)
     close(f)
   else:
-    rawMessage(errCannotOpenFile, outfile)
+    rawMessage(g.config, errGenerated, "cannot open file: " & outfile)
 
 proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) =
-  initSrcGen(r, renderFlags)
+  initSrcGen(r, renderFlags, newPartialConfigRef())
   gsub(r, n)
 
 proc getNextTok*(r: var TSrcGen, kind: var TTokType, literal: var string) =
diff --git a/compiler/reorder.nim b/compiler/reorder.nim
index 2542a08ea..d50be1d99 100644
--- a/compiler/reorder.nim
+++ b/compiler/reorder.nim
@@ -1,7 +1,8 @@
 
 import
   intsets, ast, idents, algorithm, renderer, parser, ospaths, strutils,
-  sequtils, msgs, modulegraphs, syntaxes, options, modulepaths, tables
+  sequtils, msgs, modulegraphs, syntaxes, options, modulepaths, tables,
+  configuration
 
 type
   DepN = ref object
@@ -151,10 +152,10 @@ proc expandIncludes(graph: ModuleGraph, module: PSym, n: PNode,
   for a in n:
     if a.kind == nkIncludeStmt:
       for i in 0..<a.len:
-        var f = checkModuleName(a.sons[i])
+        var f = checkModuleName(graph.config, a.sons[i])
         if f != InvalidFileIDX:
           if containsOrIncl(includedFiles, f.int):
-            localError(a.info, errRecursiveDependencyX, f.toFilename)
+            localError(graph.config, a.info, "recursive dependency: '$1'" % f.toFilename)
           else:
             let nn = includeModule(graph, module, f, cache)
             let nnn = expandIncludes(graph, module, nn, modulePath,
@@ -189,7 +190,7 @@ proc haveSameKind(dns: seq[DepN]): bool =
     if dn.pnode.kind != kind:
       return false
 
-proc mergeSections(comps: seq[seq[DepN]], res: PNode) =
+proc mergeSections(conf: ConfigRef; comps: seq[seq[DepN]], res: PNode) =
   # Merges typeSections and ConstSections when they form
   # a strong component (ex: circular type definition)
   for c in comps:
@@ -229,7 +230,7 @@ proc mergeSections(comps: seq[seq[DepN]], res: PNode) =
                     wmsg &= "line " & $cs[^1].pnode.info.line &
                       " depends on line " & $cs[j].pnode.info.line &
                       ": " & cs[^1].expls[ci] & "\n"
-          message(cs[0].pnode.info, warnUser, wmsg)
+          message(conf, cs[0].pnode.info, warnUser, wmsg)
 
           var i = 0
           while i < cs.len:
@@ -441,4 +442,4 @@ proc reorder*(graph: ModuleGraph, n: PNode, module: PSym, cache: IdentCache): PN
 
   var g = buildGraph(n, deps)
   let comps = getStrongComponents(g)
-  mergeSections(comps, result)
+  mergeSections(graph.config, comps, result)
diff --git a/compiler/rodread.nim b/compiler/rodread.nim
index f55c3279c..52e7a924c 100644
--- a/compiler/rodread.nim
+++ b/compiler/rodread.nim
@@ -90,7 +90,8 @@
 
 import
   os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms,
-  ropes, idents, std / sha1, idgen, types, rodutils, memfiles, tables
+  ropes, idents, std / sha1, idgen, types, rodutils, memfiles, tables,
+  configuration
 
 type
   TReasonForRecompile* = enum ## all the reasons that can trigger recompilation
@@ -143,6 +144,7 @@ type
     origFile: string
     inViewMode: bool
     cache*: IdentCache
+    config: ConfigRef
 
   PRodReader* = ref TRodReader
 
@@ -222,14 +224,14 @@ proc decodeNodeLazyBody(r: PRodReader, fInfo: TLineInfo,
         var fl = decodeStr(r.s, r.pos)
         result.ident = r.cache.getIdent(fl)
       else:
-        internalError(result.info, "decodeNode: nkIdent")
+        internalError(r.config, result.info, "decodeNode: nkIdent")
     of nkSym:
       if r.s[r.pos] == '!':
         inc(r.pos)
         var id = decodeVInt(r.s, r.pos)
         result.sym = rrGetSym(r, id, result.info)
       else:
-        internalError(result.info, "decodeNode: nkSym")
+        internalError(r.config, result.info, "decodeNode: nkSym")
     else:
       var i = 0
       while r.s[r.pos] != ')':
@@ -241,9 +243,9 @@ proc decodeNodeLazyBody(r: PRodReader, fInfo: TLineInfo,
           addSonNilAllowed(result, decodeNodeLazyBody(r, result.info, nil))
         inc i
     if r.s[r.pos] == ')': inc(r.pos)
-    else: internalError(result.info, "decodeNode: ')' missing")
+    else: internalError(r.config, result.info, "decodeNode: ')' missing")
   else:
-    internalError(fInfo, "decodeNode: '(' missing " & $r.pos)
+    internalError(r.config, fInfo, "decodeNode: '(' missing " & $r.pos)
 
 proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
   result = decodeNodeLazyBody(r, fInfo, nil)
@@ -277,7 +279,7 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) =
     else:
       loc.r = nil
     if r.s[r.pos] == '>': inc(r.pos)
-    else: internalError(info, "decodeLoc " & r.s[r.pos])
+    else: internalError(r.config, info, "decodeLoc " & r.s[r.pos])
 
 proc decodeType(r: PRodReader, info: TLineInfo): PType =
   result = nil
@@ -294,7 +296,7 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
     setId(result.id)
     if debugIds: registerID(result)
   else:
-    internalError(info, "decodeType: no id")
+    internalError(r.config, info, "decodeType: no id")
   # here this also avoids endless recursion for recursive type
   idTablePut(gTypeTable, result, result)
   if r.s[r.pos] == '(': result.n = decodeNode(r, unknownLineInfo())
@@ -345,14 +347,14 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
     doAssert r.s[r.pos] == '\20'
     inc(r.pos)
     let y = rrGetSym(r, decodeVInt(r.s, r.pos), info)
-    result.methods.safeAdd((x, y))
+    result.methods.add((x, y))
   decodeLoc(r, result.loc, info)
   while r.s[r.pos] == '^':
     inc(r.pos)
     if r.s[r.pos] == '(':
       inc(r.pos)
       if r.s[r.pos] == ')': inc(r.pos)
-      else: internalError(info, "decodeType ^(" & r.s[r.pos])
+      else: internalError(r.config, info, "decodeType ^(" & r.s[r.pos])
       rawAddSon(result, nil)
     else:
       var d = decodeVInt(r.s, r.pos)
@@ -364,10 +366,10 @@ proc decodeLib(r: PRodReader, info: TLineInfo): PLib =
     new(result)
     inc(r.pos)
     result.kind = TLibKind(decodeVInt(r.s, r.pos))
-    if r.s[r.pos] != '|': internalError("decodeLib: 1")
+    if r.s[r.pos] != '|': internalError(r.config, "decodeLib: 1")
     inc(r.pos)
     result.name = rope(decodeStr(r.s, r.pos))
-    if r.s[r.pos] != '|': internalError("decodeLib: 2")
+    if r.s[r.pos] != '|': internalError(r.config, "decodeLib: 2")
     inc(r.pos)
     result.path = decodeNode(r, info)
 
@@ -385,7 +387,7 @@ proc decodeInstantiations(r: PRodReader; info: TLineInfo;
     if r.s[r.pos] == '\20':
       inc(r.pos)
       ii.compilesId = decodeVInt(r.s, r.pos)
-    s.safeAdd ii
+    s.add ii
 
 proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
   var
@@ -403,12 +405,12 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
     id = decodeVInt(r.s, r.pos)
     setId(id)
   else:
-    internalError(info, "decodeSym: no id")
+    internalError(r.config, info, "decodeSym: no id")
   if r.s[r.pos] == '&':
     inc(r.pos)
     ident = r.cache.getIdent(decodeStr(r.s, r.pos))
   else:
-    internalError(info, "decodeSym: no ident")
+    internalError(r.config, info, "decodeSym: no ident")
   #echo "decoding: {", ident.s
   result = r.syms.getOrDefault(id)
   if result == nil:
@@ -417,7 +419,7 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
     r.syms[result.id] = result
     if debugIds: registerID(result)
   elif result.id != id:
-    internalError(info, "decodeSym: wrong id")
+    internalError(r.config, info, "decodeSym: wrong id")
   elif result.kind != skStub and not r.inViewMode:
     # we already loaded the symbol
     return
@@ -465,7 +467,7 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
   of skType, skGenericParam:
     while r.s[r.pos] == '\14':
       inc(r.pos)
-      result.typeInstCache.safeAdd rrGetType(r, decodeVInt(r.s, r.pos), result.info)
+      result.typeInstCache.add rrGetType(r, decodeVInt(r.s, r.pos), result.info)
   of routineKinds:
     decodeInstantiations(r, result.info, result.procInstCache)
     if r.s[r.pos] == '\16':
@@ -512,7 +514,7 @@ proc skipSection(r: PRodReader) =
       else: discard
       inc(r.pos)
   else:
-    internalError("skipSection " & $r.line)
+    internalError(r.config, "skipSection " & $r.line)
 
 proc rdWord(r: PRodReader): string =
   result = ""
@@ -530,7 +532,7 @@ proc newStub(r: PRodReader, name: string, id: int): PSym =
   if debugIds: registerID(result)
 
 proc processInterf(r: PRodReader, module: PSym) =
-  if r.interfIdx == 0: internalError("processInterf")
+  if r.interfIdx == 0: internalError(r.config, "processInterf")
   r.pos = r.interfIdx
   while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'):
     var w = decodeStr(r.s, r.pos)
@@ -543,7 +545,7 @@ proc processInterf(r: PRodReader, module: PSym) =
     r.syms[s.id] = s
 
 proc processCompilerProcs(r: PRodReader, module: PSym) =
-  if r.compilerProcsIdx == 0: internalError("processCompilerProcs")
+  if r.compilerProcsIdx == 0: internalError(r.config, "processCompilerProcs")
   r.pos = r.compilerProcsIdx
   while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'):
     var w = decodeStr(r.s, r.pos)
@@ -621,26 +623,26 @@ proc processRodFile(r: PRodReader, hash: SecureHash) =
     of "OPTIONS":
       inc(r.pos)              # skip ':'
       r.options = cast[TOptions](int32(decodeVInt(r.s, r.pos)))
-      if options.gOptions != r.options: r.reason = rrOptions
+      if r.config.options != r.options: r.reason = rrOptions
     of "GOPTIONS":
       inc(r.pos)              # skip ':'
       var dep = cast[TGlobalOptions](int32(decodeVInt(r.s, r.pos)))
-      if gGlobalOptions-harmlessOptions != dep-harmlessOptions:
+      if r.config.globalOptions-harmlessOptions != dep-harmlessOptions:
         r.reason = rrOptions
     of "CMD":
       inc(r.pos)              # skip ':'
       var dep = cast[TCommands](int32(decodeVInt(r.s, r.pos)))
-      if cmdChangeTriggersRecompilation(dep, gCmd): r.reason = rrOptions
+      if cmdChangeTriggersRecompilation(dep, r.config.cmd): r.reason = rrOptions
     of "DEFINES":
       inc(r.pos)              # skip ':'
       d = 0
       while r.s[r.pos] > '\x0A':
         w = decodeStr(r.s, r.pos)
         inc(d)
-        if not condsyms.isDefined(r.cache.getIdent(w)):
+        if not isDefined(r.config, w):
           r.reason = rrDefines #MessageOut('not defined, but should: ' + w);
         if r.s[r.pos] == ' ': inc(r.pos)
-      if d != countDefinedSymbols(): r.reason = rrDefines
+      if d != countDefinedSymbols(r.config.symbols): r.reason = rrDefines
     of "FILES":
       inc(r.pos, 2)           # skip "(\10"
       inc(r.line)
@@ -648,7 +650,7 @@ proc processRodFile(r: PRodReader, hash: SecureHash) =
         let finalPath = decodeStr(r.s, r.pos)
         #let resolvedPath = relativePath.findModule(r.origFile)
         #let finalPath = if resolvedPath.len > 0: resolvedPath else: relativePath
-        r.files.add(finalPath.fileInfoIdx)
+        r.files.add(fileInfoIdx(r.config, finalPath))
         inc(r.pos)            # skip #10
         inc(r.line)
       if r.s[r.pos] == ')': inc(r.pos)
@@ -696,7 +698,7 @@ proc processRodFile(r: PRodReader, hash: SecureHash) =
       r.initIdx = r.pos + 2   # "(\10"
       skipSection(r)
     else:
-      internalError("invalid section: '" & section &
+      internalError(r.config, "invalid section: '" & section &
                     "' at " & $r.line & " in " & r.filename)
       #MsgWriteln("skipping section: " & section &
       #           " at " & $r.line & " in " & r.filename)
@@ -712,9 +714,11 @@ proc startsWith(buf: cstring, token: string, pos = 0): bool =
   result = s == token.len
 
 proc newRodReader(modfilename: string, hash: SecureHash,
-                  readerIndex: int; cache: IdentCache): PRodReader =
+                  readerIndex: int; cache: IdentCache;
+                  config: ConfigRef): PRodReader =
   new(result)
   result.cache = cache
+  result.config = config
   try:
     result.memfile = memfiles.open(modfilename)
   except OSError:
@@ -757,13 +761,13 @@ proc rrGetType(r: PRodReader, id: int, info: TLineInfo): PType =
     # load the type:
     var oldPos = r.pos
     var d = iiTableGet(r.index.tab, id)
-    if d == InvalidKey: internalError(info, "rrGetType")
+    if d == InvalidKey: internalError(r.config, info, "rrGetType")
     r.pos = d + r.dataIdx
     result = decodeType(r, info)
     r.pos = oldPos
 
 type
-  TFileModuleRec{.final.} = object
+  TFileModuleRec = object
     filename*: string
     reason*: TReasonForRecompile
     rd*: PRodReader
@@ -776,7 +780,7 @@ var gMods*: TFileModuleMap = @[]
 
 proc decodeSymSafePos(rd: PRodReader, offset: int, info: TLineInfo): PSym =
   # all compiled modules
-  if rd.dataIdx == 0: internalError(info, "dataIdx == 0")
+  if rd.dataIdx == 0: internalError(rd.config, info, "dataIdx == 0")
   var oldPos = rd.pos
   rd.pos = offset + rd.dataIdx
   result = decodeSym(rd, info)
@@ -811,7 +815,7 @@ proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
       if moduleID < 0:
         var x = ""
         encodeVInt(id, x)
-        internalError(info, "missing from both indexes: +" & x)
+        internalError(r.config, info, "missing from both indexes: +" & x)
       var rd = getReader(moduleID)
       doAssert rd != nil
       d = iiTableGet(rd.index.tab, id)
@@ -821,14 +825,14 @@ proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
         var x = ""
         encodeVInt(id, x)
         when false: findSomeWhere(id)
-        internalError(info, "rrGetSym: no reader found: +" & x)
+        internalError(r.config, info, "rrGetSym: no reader found: +" & x)
     else:
       # own symbol:
       result = decodeSymSafePos(r, d, info)
   if result != nil and result.kind == skStub: rawLoadStub(result)
 
 proc loadInitSection*(r: PRodReader): PNode =
-  if r.initIdx == 0 or r.dataIdx == 0: internalError("loadInitSection")
+  if r.initIdx == 0 or r.dataIdx == 0: internalError(r.config, "loadInitSection")
   var oldPos = r.pos
   r.pos = r.initIdx
   result = newNode(nkStmtList)
@@ -845,7 +849,7 @@ proc loadConverters(r: PRodReader) =
   # We have to ensure that no exported converter is a stub anymore, and the
   # import mechanism takes care of the rest.
   if r.convertersIdx == 0 or r.dataIdx == 0:
-    internalError("importConverters")
+    internalError(r.config, "importConverters")
   r.pos = r.convertersIdx
   while r.s[r.pos] > '\x0A':
     var d = decodeVInt(r.s, r.pos)
@@ -854,7 +858,7 @@ proc loadConverters(r: PRodReader) =
 
 proc loadMethods(r: PRodReader) =
   if r.methodsIdx == 0 or r.dataIdx == 0:
-    internalError("loadMethods")
+    internalError(r.config, "loadMethods")
   r.pos = r.methodsIdx
   while r.s[r.pos] > '\x0A':
     var d = decodeVInt(r.s, r.pos)
@@ -872,7 +876,7 @@ proc getHash*(fileIdx: FileIndex): SecureHash =
 template growCache*(cache, pos) =
   if cache.len <= pos: cache.setLen(pos+1)
 
-proc checkDep(fileIdx: FileIndex; cache: IdentCache): TReasonForRecompile =
+proc checkDep(fileIdx: FileIndex; cache: IdentCache; conf: ConfigRef): TReasonForRecompile =
   assert fileIdx != InvalidFileIDX
   growCache gMods, fileIdx.int32
   if gMods[fileIdx.int32].reason != rrEmpty:
@@ -882,8 +886,8 @@ proc checkDep(fileIdx: FileIndex; cache: IdentCache): TReasonForRecompile =
   var hash = getHash(fileIdx)
   gMods[fileIdx.int32].reason = rrNone  # we need to set it here to avoid cycles
   result = rrNone
-  var rodfile = toGeneratedFile(filename.withPackageName, RodExt)
-  var r = newRodReader(rodfile, hash, fileIdx.int32, cache)
+  var rodfile = toGeneratedFile(conf, conf.withPackageName(filename), RodExt)
+  var r = newRodReader(rodfile, hash, fileIdx.int32, cache, conf)
   if r == nil:
     result = (if existsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)
   else:
@@ -894,30 +898,30 @@ proc checkDep(fileIdx: FileIndex; cache: IdentCache): TReasonForRecompile =
       # NOTE: we need to process the entire module graph so that no ID will
       # be used twice! However, compilation speed does not suffer much from
       # this, since results are cached.
-      var res = checkDep(systemFileIdx, cache)
+      var res = checkDep(systemFileIdx, cache, conf)
       if res != rrNone: result = rrModDeps
       for i in countup(0, high(r.modDeps)):
-        res = checkDep(r.modDeps[i], cache)
+        res = checkDep(r.modDeps[i], cache, conf)
         if res != rrNone:
           result = rrModDeps
           # we cannot break here, because of side-effects of `checkDep`
   if result != rrNone:
-    rawMessage(hintProcessing, reasonToFrmt[result] % filename)
-  if result != rrNone or optForceFullMake in gGlobalOptions:
+    rawMessage(conf, hintProcessing, reasonToFrmt[result] % filename)
+  if result != rrNone or optForceFullMake in conf.globalOptions:
     # recompilation is necessary:
     if r != nil: memfiles.close(r.memfile)
     r = nil
   gMods[fileIdx.int32].rd = r
   gMods[fileIdx.int32].reason = result  # now we know better
 
-proc handleSymbolFile*(module: PSym; cache: IdentCache): PRodReader =
-  if gSymbolFiles in {disabledSf, writeOnlySf, v2Sf}:
+proc handleSymbolFile*(module: PSym; cache: IdentCache; conf: ConfigRef): PRodReader =
+  if conf.symbolFiles in {disabledSf, writeOnlySf, v2Sf}:
     module.id = getID()
     return nil
-  idgen.loadMaxIds(options.gProjectPath / options.gProjectName)
+  idgen.loadMaxIds(conf, conf.projectPath / conf.projectName)
   let fileIdx = module.fileIdx
-  discard checkDep(fileIdx, cache)
-  if gMods[fileIdx.int32].reason == rrEmpty: internalError("handleSymbolFile")
+  discard checkDep(fileIdx, cache, conf)
+  #if gMods[fileIdx.int32].reason == rrEmpty: internalError("handleSymbolFile")
   result = gMods[fileIdx.int32].rd
   if result != nil:
     module.id = result.moduleID
@@ -930,19 +934,20 @@ proc handleSymbolFile*(module: PSym; cache: IdentCache): PRodReader =
     module.id = getID()
 
 proc rawLoadStub(s: PSym) =
-  if s.kind != skStub: internalError("loadStub")
+  assert s.kind == skStub
+  #if s.kind != skStub: internalError("loadStub")
   var rd = gMods[s.position].rd
   var theId = s.id                # used for later check
   var d = iiTableGet(rd.index.tab, s.id)
-  if d == InvalidKey: internalError("loadStub: invalid key")
+  #if d == InvalidKey: internalError("loadStub: invalid key")
   var rs = decodeSymSafePos(rd, d, unknownLineInfo())
-  if rs != s:
-    #echo "rs: ", toHex(cast[int](rs.position), int.sizeof * 2),
-    #     "\ns:  ", toHex(cast[int](s.position), int.sizeof * 2)
-    internalError(rs.info, "loadStub: wrong symbol")
-  elif rs.id != theId:
-    internalError(rs.info, "loadStub: wrong ID")
-  #MessageOut('loaded stub: ' + s.name.s);
+  when false:
+    if rs != s:
+      #echo "rs: ", toHex(cast[int](rs.position), int.sizeof * 2),
+      #     "\ns:  ", toHex(cast[int](s.position), int.sizeof * 2)
+      internalError(rs.info, "loadStub: wrong symbol")
+    elif rs.id != theId:
+      internalError(rs.info, "loadStub: wrong ID")
 
 proc loadStub*(s: PSym) =
   ## loads the stub symbol `s`.
@@ -1030,9 +1035,8 @@ proc writeSym(f: File; s: PSym) =
   if s.magic != mNone:
     f.write('@')
     f.write($s.magic)
-  if s.options != gOptions:
-    f.write('!')
-    f.write($s.options)
+  f.write('!')
+  f.write($s.options)
   if s.position != 0:
     f.write('%')
     f.write($s.position)
@@ -1083,9 +1087,10 @@ proc writeType(f: File; t: PType) =
   f.write("]\n")
 
 proc viewFile(rodfile: string) =
-  var r = newRodReader(rodfile, secureHash(""), 0, newIdentCache())
+  let conf = newConfigRef()
+  var r = newRodReader(rodfile, secureHash(""), 0, newIdentCache(), conf)
   if r == nil:
-    rawMessage(errGenerated, "cannot open file (or maybe wrong version):" &
+    rawMessage(conf, errGenerated, "cannot open file (or maybe wrong version):" &
        rodfile)
     return
   r.inViewMode = true
@@ -1133,9 +1138,9 @@ proc viewFile(rodfile: string) =
       outf.write("FILES(\n")
       while r.s[r.pos] != ')':
         let relativePath = decodeStr(r.s, r.pos)
-        let resolvedPath = relativePath.findModule(r.origFile)
+        let resolvedPath = findModule(conf, relativePath, r.origFile)
         let finalPath = if resolvedPath.len > 0: resolvedPath else: relativePath
-        r.files.add(finalPath.fileInfoIdx)
+        r.files.add(fileInfoIdx(conf, finalPath))
         inc(r.pos)            # skip #10
         inc(r.line)
         outf.writeLine finalPath
@@ -1227,7 +1232,7 @@ proc viewFile(rodfile: string) =
       if r.s[r.pos] == ')': inc r.pos
       outf.write("<not supported by viewer>)\n")
     else:
-      internalError("invalid section: '" & section &
+      internalError(r.config, "invalid section: '" & section &
                     "' at " & $r.line & " in " & r.filename)
       skipSection(r)
     if r.s[r.pos] == '\x0A':
diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim
index 0ae687268..4686baf2b 100644
--- a/compiler/rodwrite.nim
+++ b/compiler/rodwrite.nim
@@ -37,12 +37,13 @@ type
     files: TStringSeq
     origFile: string
     cache: IdentCache
+    config: ConfigRef
 
   PRodWriter = ref TRodWriter
 
-proc getDefines(): string =
+proc getDefines(conf: ConfigRef): string =
   result = ""
-  for d in definedSymbolNames():
+  for d in definedSymbolNames(conf.symbols):
     if result.len != 0: add(result, " ")
     add(result, d)
 
@@ -57,8 +58,10 @@ proc fileIdx(w: PRodWriter, filename: string): int =
 template filename*(w: PRodWriter): string =
   toFilename(FileIndex w.module.position)
 
-proc newRodWriter(hash: SecureHash, module: PSym; cache: IdentCache): PRodWriter =
+proc newRodWriter(hash: SecureHash, module: PSym; cache: IdentCache;
+                  config: ConfigRef): PRodWriter =
   new(result)
+  result.config = config
   result.sstack = @[]
   result.tstack = @[]
   initIiTable(result.index.tab)
@@ -67,8 +70,8 @@ proc newRodWriter(hash: SecureHash, module: PSym; cache: IdentCache): PRodWriter
   result.imports.r = ""
   result.hash = hash
   result.module = module
-  result.defines = getDefines()
-  result.options = options.gOptions
+  result.defines = getDefines(config)
+  result.options = config.options
   result.files = @[]
   result.inclDeps = ""
   result.modDeps = ""
@@ -83,14 +86,14 @@ proc newRodWriter(hash: SecureHash, module: PSym; cache: IdentCache): PRodWriter
 
 proc addModDep(w: PRodWriter, dep: string; info: TLineInfo) =
   if w.modDeps.len != 0: add(w.modDeps, ' ')
-  let resolved = dep.findModule(info.toFullPath)
+  let resolved = findModule(w.config, dep, info.toFullPath)
   encodeVInt(fileIdx(w, resolved), w.modDeps)
 
 const
   rodNL = "\x0A"
 
 proc addInclDep(w: PRodWriter, dep: string; info: TLineInfo) =
-  let resolved = dep.findModule(info.toFullPath)
+  let resolved = findModule(w.config, dep, info.toFullPath)
   encodeVInt(fileIdx(w, resolved), w.inclDeps)
   add(w.inclDeps, " ")
   encodeStr($secureHashFile(resolved), w.inclDeps)
@@ -201,7 +204,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
     result.add("[]")
     return
   # we need no surrounding [] here because the type is in a line of its own
-  if t.kind == tyForward: internalError("encodeType: tyForward")
+  if t.kind == tyForward: internalError(w.config, "encodeType: tyForward")
   # for the new rodfile viewer we use a preceding [ so that the data section
   # can easily be disambiguated:
   add(result, '[')
@@ -454,7 +457,7 @@ proc processStacks(w: PRodWriter, finalPass: bool) =
     oldS = slen
     oldT = tlen
   if finalPass and (oldS != 0 or oldT != 0):
-    internalError("could not serialize some forwarded symbols/types")
+    internalError(w.config, "could not serialize some forwarded symbols/types")
 
 proc rawAddInterfaceSym(w: PRodWriter, s: PSym) =
   pushSym(w, s)
@@ -476,8 +479,8 @@ proc addStmt(w: PRodWriter, n: PNode) =
 proc writeRod(w: PRodWriter) =
   processStacks(w, true)
   var f: File
-  if not open(f, completeGeneratedFilePath(changeFileExt(
-                      w.filename.withPackageName, RodExt)),
+  if not open(f, completeGeneratedFilePath(w.config, changeFileExt(
+                      withPackageName(w.config, w.filename), RodExt)),
               fmWrite):
     #echo "couldn't write rod file for: ", w.filename
     return
@@ -506,12 +509,12 @@ proc writeRod(w: PRodWriter) =
   f.write(rodNL)
 
   var goptions = "GOPTIONS:"
-  encodeVInt(cast[int32](gGlobalOptions), goptions)
+  encodeVInt(cast[int32](w.config.globalOptions), goptions)
   f.write(goptions)
   f.write(rodNL)
 
   var cmd = "CMD:"
-  encodeVInt(cast[int32](gCmd), cmd)
+  encodeVInt(cast[int32](w.config.cmd), cmd)
   f.write(cmd)
   f.write(rodNL)
 
@@ -587,17 +590,17 @@ proc process(c: PPassContext, n: PNode): PNode =
   of nkProcDef, nkFuncDef, nkIteratorDef, nkConverterDef,
       nkTemplateDef, nkMacroDef:
     let s = n.sons[namePos].sym
-    if s == nil: internalError(n.info, "rodwrite.process")
+    if s == nil: internalError(w.config, n.info, "rodwrite.process")
     if n.sons[bodyPos] == nil:
-      internalError(n.info, "rodwrite.process: body is nil")
+      internalError(w.config, n.info, "rodwrite.process: body is nil")
     if n.sons[bodyPos].kind != nkEmpty or s.magic != mNone or
         sfForward notin s.flags:
       addInterfaceSym(w, s)
   of nkMethodDef:
     let s = n.sons[namePos].sym
-    if s == nil: internalError(n.info, "rodwrite.process")
+    if s == nil: internalError(w.config, n.info, "rodwrite.process")
     if n.sons[bodyPos] == nil:
-      internalError(n.info, "rodwrite.process: body is nil")
+      internalError(w.config, n.info, "rodwrite.process: body is nil")
     if n.sons[bodyPos].kind != nkEmpty or s.magic != mNone or
         sfForward notin s.flags:
       pushSym(w, s)
@@ -612,7 +615,7 @@ proc process(c: PPassContext, n: PNode): PNode =
     for i in countup(0, sonsLen(n) - 1):
       var a = n.sons[i]
       if a.kind == nkCommentStmt: continue
-      if a.sons[0].kind != nkSym: internalError(a.info, "rodwrite.process")
+      if a.sons[0].kind != nkSym: internalError(w.config, a.info, "rodwrite.process")
       var s = a.sons[0].sym
       addInterfaceSym(w, s)
       # this takes care of enum fields too
@@ -627,22 +630,22 @@ proc process(c: PPassContext, n: PNode): PNode =
       #        end
   of nkImportStmt:
     for i in countup(0, sonsLen(n) - 1):
-      addModDep(w, getModuleName(n.sons[i]), n.info)
+      addModDep(w, getModuleName(w.config, n.sons[i]), n.info)
     addStmt(w, n)
   of nkFromStmt, nkImportExceptStmt:
-    addModDep(w, getModuleName(n.sons[0]), n.info)
+    addModDep(w, getModuleName(w.config, n.sons[0]), n.info)
     addStmt(w, n)
   of nkIncludeStmt:
     for i in countup(0, sonsLen(n) - 1):
-      addInclDep(w, getModuleName(n.sons[i]), n.info)
+      addInclDep(w, getModuleName(w.config, n.sons[i]), n.info)
   of nkPragma:
     addStmt(w, n)
   else:
     discard
 
 proc myOpen(g: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
-  if module.id < 0: internalError("rodwrite: module ID not set")
-  var w = newRodWriter(rodread.getHash FileIndex module.position, module, cache)
+  if module.id < 0: internalError(g.config, "rodwrite: module ID not set")
+  var w = newRodWriter(rodread.getHash FileIndex module.position, module, cache, g.config)
   rawAddInterfaceSym(w, module)
   result = w
 
@@ -650,7 +653,7 @@ proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode =
   result = process(c, n)
   var w = PRodWriter(c)
   writeRod(w)
-  idgen.saveMaxIds(options.gProjectPath / options.gProjectName)
+  idgen.saveMaxIds(graph.config, graph.config.projectPath / graph.config.projectName)
 
 const rodwritePass* = makePass(open = myOpen, close = myClose, process = process)
 
diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim
index 6ef42f15e..30e5e4803 100644
--- a/compiler/scriptconfig.nim
+++ b/compiler/scriptconfig.nim
@@ -13,7 +13,7 @@
 import
   ast, modules, idents, passes, passaux, condsyms,
   options, nimconf, sem, semdata, llstream, vm, vmdef, commands, msgs,
-  os, times, osproc, wordrecg, strtabs, modulegraphs
+  os, times, osproc, wordrecg, strtabs, modulegraphs, configuration
 
 # we support 'cmpIgnoreStyle' natively for efficiency:
 from strutils import cmpIgnoreStyle, contains
@@ -26,11 +26,12 @@ proc listDirs(a: VmArgs, filter: set[PathComponent]) =
   setResult(a, result)
 
 proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
-              config: ConfigRef): PEvalContext =
+              graph: ModuleGraph): PEvalContext =
   # For Nimble we need to export 'setupVM'.
-  result = newCtx(module, cache, config)
+  result = newCtx(module, cache, graph)
   result.mode = emRepl
   registerAdditionalOps(result)
+  let conf = graph.config
 
   # captured vars:
   var errorMsg: string
@@ -98,13 +99,13 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
   cbconf thisDir:
     setResult(a, vthisDir)
   cbconf put:
-    options.setConfigVar(getString(a, 0), getString(a, 1))
+    options.setConfigVar(conf, getString(a, 0), getString(a, 1))
   cbconf get:
-    setResult(a, options.getConfigVar(a.getString 0))
+    setResult(a, options.getConfigVar(conf, a.getString 0))
   cbconf exists:
-    setResult(a, options.existsConfigVar(a.getString 0))
+    setResult(a, options.existsConfigVar(conf, a.getString 0))
   cbconf nimcacheDir:
-    setResult(a, options.getNimcacheDir())
+    setResult(a, options.getNimcacheDir(conf))
   cbconf paramStr:
     setResult(a, os.paramStr(int a.getInt 0))
   cbconf paramCount:
@@ -114,67 +115,66 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
   cbconf cmpIgnoreCase:
     setResult(a, strutils.cmpIgnoreCase(a.getString 0, a.getString 1))
   cbconf setCommand:
-    options.command = a.getString 0
+    conf.command = a.getString 0
     let arg = a.getString 1
     if arg.len > 0:
-      gProjectName = arg
+      conf.projectName = arg
       let path =
-        if gProjectName.isAbsolute: gProjectName
-        else: gProjectPath / gProjectName
+        if conf.projectName.isAbsolute: conf.projectName
+        else: conf.projectPath / conf.projectName
       try:
-        gProjectFull = canonicalizePath(path)
+        conf.projectFull = canonicalizePath(conf, path)
       except OSError:
-        gProjectFull = path
+        conf.projectFull = path
   cbconf getCommand:
-    setResult(a, options.command)
+    setResult(a, conf.command)
   cbconf switch:
-    processSwitch(a.getString 0, a.getString 1, passPP, module.info, config)
+    processSwitch(a.getString 0, a.getString 1, passPP, module.info, conf)
   cbconf hintImpl:
     processSpecificNote(a.getString 0, wHint, passPP, module.info,
-      a.getString 1)
+      a.getString 1, conf)
   cbconf warningImpl:
     processSpecificNote(a.getString 0, wWarning, passPP, module.info,
-      a.getString 1)
+      a.getString 1, conf)
   cbconf patchFile:
     let key = a.getString(0) & "_" & a.getString(1)
     var val = a.getString(2).addFileExt(NimExt)
     if {'$', '~'} in val:
-      val = pathSubs(val, vthisDir)
+      val = pathSubs(conf, val, vthisDir)
     elif not isAbsolute(val):
       val = vthisDir / val
-    gModuleOverrides[key] = val
+    conf.moduleOverrides[key] = val
   cbconf selfExe:
     setResult(a, os.getAppFilename())
   cbconf cppDefine:
-    if config != nil:
-      options.cppDefine(config, a.getString(0))
+    options.cppDefine(conf, a.getString(0))
 
 proc runNimScript*(cache: IdentCache; scriptName: string;
-                   freshDefines=true; config: ConfigRef) =
-  rawMessage(hintConf, scriptName)
+                   freshDefines=true; conf: ConfigRef) =
+  rawMessage(conf, hintConf, scriptName)
   passes.gIncludeFile = includeModule
   passes.gImportModule = importModule
-  let graph = newModuleGraph(config)
-  if freshDefines: initDefines()
+  let graph = newModuleGraph(conf)
+  if freshDefines: initDefines(conf.symbols)
 
-  defineSymbol("nimscript")
-  defineSymbol("nimconfig")
+  defineSymbol(conf.symbols, "nimscript")
+  defineSymbol(conf.symbols, "nimconfig")
   registerPass(semPass)
   registerPass(evalPass)
 
-  searchPaths.add(options.libpath)
+  conf.searchPaths.add(conf.libpath)
 
   var m = graph.makeModule(scriptName)
   incl(m.flags, sfMainModule)
-  vm.globalCtx = setupVM(m, cache, scriptName, config)
+  vm.globalCtx = setupVM(m, cache, scriptName, graph)
 
   graph.compileSystemModule(cache)
   discard graph.processModule(m, llStreamOpen(scriptName, fmRead), nil, cache)
 
   # ensure we load 'system.nim' again for the real non-config stuff!
-  resetSystemArtifacts()
+  resetSystemArtifacts(graph)
   vm.globalCtx = nil
   # do not remove the defined symbols
   #initDefines()
-  undefSymbol("nimscript")
-  undefSymbol("nimconfig")
+  undefSymbol(conf.symbols, "nimscript")
+  undefSymbol(conf.symbols, "nimconfig")
diff --git a/compiler/sem.nim b/compiler/sem.nim
index d8e5b7f20..c5c3dd99b 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -16,7 +16,7 @@ import
   procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
   intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
   evaltempl, patterns, parampatterns, sempass2, nimfix.pretty, semmacrosanity,
-  semparallel, lowerings, pluginsupport, plugins.active, rod
+  semparallel, lowerings, pluginsupport, plugins.active, rod, configuration
 
 from modulegraphs import ModuleGraph
 
@@ -33,7 +33,7 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
 proc semProcBody(c: PContext, n: PNode): PNode
 
 proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode
-proc changeType(n: PNode, newType: PType, check: bool)
+proc changeType(c: PContext; n: PNode, newType: PType, check: bool)
 
 proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode
 proc semTypeNode(c: PContext, n: PNode, prev: PType): PType
@@ -64,14 +64,14 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode;
   # templates perform some quick check whether the cursor is actually in
   # the generic or template.
   when defined(nimsuggest):
-    if gCmd == cmdIdeTools and requiresCheck:
+    if c.config.cmd == cmdIdeTools and requiresCheck:
       #if optIdeDebug in gGlobalOptions:
       #  echo "passing to safeSemExpr: ", renderTree(n)
       discard safeSemExpr(c, n)
 
 proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
   if arg.typ.isNil:
-    localError(arg.info, errExprXHasNoType,
+    localError(c.config, arg.info, "expression has no type: " &
                renderTree(arg, {renderNoComments}))
     # error correction:
     result = copyTree(arg)
@@ -79,14 +79,14 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
   else:
     result = indexTypesMatch(c, formal, arg.typ, arg)
     if result == nil:
-      typeMismatch(info, formal, arg.typ)
+      typeMismatch(c.config, info, formal, arg.typ)
       # error correction:
       result = copyTree(arg)
       result.typ = formal
     else:
       let x = result.skipConv
       if x.kind in {nkPar, nkTupleConstr} and formal.kind != tyExpr:
-        changeType(x, formal, check=true)
+        changeType(c, x, formal, check=true)
       else:
         result = skipHiddenSubConv(result)
         #result.typ = takeType(formal, arg.typ)
@@ -180,7 +180,7 @@ proc commonType*(x: PType, y: PNode): PType =
   commonType(x, y.typ)
 
 proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
-  result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info)
+  result = newSym(kind, considerQuotedIdent(c.config, n), getCurrOwner(c), n.info)
   when defined(nimsuggest):
     suggestDecl(c, n, result)
 
@@ -192,7 +192,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
     # and sfGenSym in n.sym.flags:
     result = n.sym
     if result.kind != kind:
-      localError(n.info, "cannot use symbol of kind '" &
+      localError(c.config, n.info, "cannot use symbol of kind '" &
                  $result.kind & "' as a '" & $kind & "'")
     if sfGenSym in result.flags and result.kind notin {skTemplate, skMacro, skParam}:
       # declarative context, so produce a fresh gensym:
@@ -204,7 +204,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
     # template; we must fix it here: see #909
     result.owner = getCurrOwner(c)
   else:
-    result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info)
+    result = newSym(kind, considerQuotedIdent(c.config, n), getCurrOwner(c), n.info)
   #if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule:
   #  incl(result.flags, sfGlobal)
   when defined(nimsuggest):
@@ -216,20 +216,20 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
 proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
                         allowed: TSymFlags): PSym
 
-proc typeAllowedCheck(info: TLineInfo; typ: PType; kind: TSymKind;
+proc typeAllowedCheck(conf: ConfigRef; info: TLineInfo; typ: PType; kind: TSymKind;
                       flags: TTypeAllowedFlags = {}) =
   let t = typeAllowed(typ, kind, flags)
   if t != nil:
     if t == typ:
-      localError(info, "invalid type: '" & typeToString(typ) &
+      localError(conf, info, "invalid type: '" & typeToString(typ) &
         "' for " & substr($kind, 2).toLowerAscii)
     else:
-      localError(info, "invalid type: '" & typeToString(t) &
+      localError(conf, info, "invalid type: '" & typeToString(t) &
         "' in this context: '" & typeToString(typ) &
         "' for " & substr($kind, 2).toLowerAscii)
 
 proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
-  typeAllowedCheck(typ.n.info, typ, skProc)
+  typeAllowedCheck(c.config, typ.n.info, typ, skProc)
 
 proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
 proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
@@ -282,10 +282,10 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
       result = evaluated
       let expectedType = eOrig.typ.skipTypes({tyStatic})
       if hasCycle(result):
-        globalError(eOrig.info, "the resulting AST is cyclic and cannot be processed further")
+        globalError(c.config, eOrig.info, "the resulting AST is cyclic and cannot be processed further")
         result = errorNode(c, eOrig)
       else:
-        semmacrosanity.annotateType(result, expectedType)
+        semmacrosanity.annotateType(result, expectedType, c.config)
   else:
     result = semExprWithType(c, evaluated)
     #result = fitNode(c, e.typ, result) inlined with special case:
@@ -302,18 +302,18 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
   var e = semExprWithType(c, n)
   if e == nil: return
 
-  result = getConstExpr(c.module, e)
+  result = getConstExpr(c.module, e, c.graph)
   if result != nil: return
 
-  let oldErrorCount = msgs.gErrorCounter
-  let oldErrorMax = msgs.gErrorMax
+  let oldErrorCount = c.config.errorCounter
+  let oldErrorMax = c.config.errorMax
   let oldErrorOutputs = errorOutputs
 
   errorOutputs = {}
-  msgs.gErrorMax = high(int)
+  c.config.errorMax = high(int)
 
   try:
-    result = evalConstExpr(c.module, c.cache, c.graph.config, e)
+    result = evalConstExpr(c.module, c.cache, c.graph, e)
     if result == nil or result.kind == nkEmpty:
       result = nil
     else:
@@ -322,26 +322,29 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
   except ERecoverableError:
     result = nil
 
-  msgs.gErrorCounter = oldErrorCount
-  msgs.gErrorMax = oldErrorMax
+  c.config.errorCounter = oldErrorCount
+  c.config.errorMax = oldErrorMax
   errorOutputs = oldErrorOutputs
 
+const
+  errConstExprExpected = "constant expression expected"
+
 proc semConstExpr(c: PContext, n: PNode): PNode =
   var e = semExprWithType(c, n)
   if e == nil:
-    localError(n.info, errConstExprExpected)
+    localError(c.config, n.info, errConstExprExpected)
     return n
-  result = getConstExpr(c.module, e)
+  result = getConstExpr(c.module, e, c.graph)
   if result == nil:
     #if e.kind == nkEmpty: globalError(n.info, errConstExprExpected)
-    result = evalConstExpr(c.module, c.cache, c.graph.config, e)
+    result = evalConstExpr(c.module, c.cache, c.graph, e)
     if result == nil or result.kind == nkEmpty:
       if e.info != n.info:
         pushInfoContext(n.info)
-        localError(e.info, errConstExprExpected)
+        localError(c.config, e.info, errConstExprExpected)
         popInfoContext()
       else:
-        localError(e.info, errConstExprExpected)
+        localError(c.config, e.info, errConstExprExpected)
       # error correction:
       result = e
     else:
@@ -356,7 +359,7 @@ proc semExprFlagDispatched(c: PContext, n: PNode, flags: TExprFlags): PNode =
   else:
     result = semExprWithType(c, n, flags)
     if efPreferStatic in flags:
-      var evaluated = getConstExpr(c.module, result)
+      var evaluated = getConstExpr(c.module, result, c.graph)
       if evaluated != nil: return evaluated
       evaluated = evalAtCompileTime(c, result)
       if evaluated != nil: return evaluated
@@ -379,7 +382,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
   ## contains.
   inc(evalTemplateCounter)
   if evalTemplateCounter > evalTemplateLimit:
-    globalError(s.info, errTemplateInstantiationTooNested)
+    globalError(c.config, s.info, "template instantiation too nested")
   c.friendModules.add(s.owner.getModule)
 
   result = macroResult
@@ -421,43 +424,46 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
   dec(evalTemplateCounter)
   discard c.friendModules.pop()
 
+const
+  errMissingGenericParamsForTemplate = "'$1' has unspecified generic parameters"
+
 proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
                   flags: TExprFlags = {}): PNode =
   pushInfoContext(nOrig.info)
 
-  markUsed(n.info, sym, c.graph.usageSym)
+  markUsed(c.config, n.info, sym, c.graph.usageSym)
   styleCheckUse(n.info, sym)
   if sym == c.p.owner:
-    globalError(n.info, errRecursiveDependencyX, sym.name.s)
+    globalError(c.config, n.info, "recursive dependency: '$1'" % sym.name.s)
 
   let genericParams = if sfImmediate in sym.flags: 0
                       else: sym.ast[genericParamsPos].len
   let suppliedParams = max(n.safeLen - 1, 0)
 
   if suppliedParams < genericParams:
-    globalError(n.info, errMissingGenericParamsForTemplate, n.renderTree)
+    globalError(c.config, n.info, errMissingGenericParamsForTemplate % n.renderTree)
 
   #if c.evalContext == nil:
   #  c.evalContext = c.createEvalContext(emStatic)
-  result = evalMacroCall(c.module, c.cache, c.graph.config, n, nOrig, sym)
+  result = evalMacroCall(c.module, c.cache, c.graph, n, nOrig, sym)
   if efNoSemCheck notin flags:
     result = semAfterMacroCall(c, n, result, sym, flags)
   result = wrapInComesFrom(nOrig.info, sym, result)
   popInfoContext()
 
 proc forceBool(c: PContext, n: PNode): PNode =
-  result = fitNode(c, getSysType(tyBool), n, n.info)
+  result = fitNode(c, getSysType(c.graph, n.info, tyBool), n, n.info)
   if result == nil: result = n
 
 proc semConstBoolExpr(c: PContext, n: PNode): PNode =
   let nn = semExprWithType(c, n)
-  result = fitNode(c, getSysType(tyBool), nn, nn.info)
+  result = fitNode(c, getSysType(c.graph, n.info, tyBool), nn, nn.info)
   if result == nil:
-    localError(n.info, errConstExprExpected)
+    localError(c.config, n.info, errConstExprExpected)
     return nn
-  result = getConstExpr(c.module, result)
+  result = getConstExpr(c.module, result, c.graph)
   if result == nil:
-    localError(n.info, errConstExprExpected)
+    localError(c.config, n.info, errConstExprExpected)
     result = nn
 
 proc semGenericStmt(c: PContext, n: PNode): PNode
@@ -470,14 +476,14 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
     var prc = c.generics[i].inst.sym
     if prc.kind in {skProc, skFunc, skMethod, skConverter} and prc.magic == mNone:
       if prc.ast == nil or prc.ast.sons[bodyPos] == nil:
-        internalError(prc.info, "no code for " & prc.name.s)
+        internalError(c.config, prc.info, "no code for " & prc.name.s)
       else:
         addSon(n, prc.ast)
   c.lastGenericIdx = c.generics.len
 
 proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
   var c = newContext(graph, module, cache)
-  if c.p != nil: internalError(module.info, "sem.myOpen")
+  if c.p != nil: internalError(graph.config, module.info, "sem.myOpen")
   c.semConstExpr = semConstExpr
   c.semExpr = semExpr
   c.semTryExpr = tryExpr
@@ -495,14 +501,14 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
   c.importTable = openScope(c)
   c.importTable.addSym(module) # a module knows itself
   if sfSystemModule in module.flags:
-    magicsys.systemModule = module # set global variable!
+    graph.systemModule = module
   c.topLevelScope = openScope(c)
   # don't be verbose unless the module belongs to the main package:
   if module.owner.id == gMainPackageId:
-    gNotes = gMainPackageNotes
+    graph.config.notes = graph.config.mainPackageNotes
   else:
-    if gMainPackageNotes == {}: gMainPackageNotes = gNotes
-    gNotes = ForeignPackageNotes
+    if graph.config.mainPackageNotes == {}: graph.config.mainPackageNotes = graph.config.notes
+    graph.config.notes = graph.config.foreignPackageNotes
   result = c
 
 proc myOpenCached(graph: ModuleGraph; module: PSym; rd: PRodReader): PPassContext =
@@ -511,30 +517,30 @@ proc myOpenCached(graph: ModuleGraph; module: PSym; rd: PRodReader): PPassContex
 proc replayMethodDefs(graph: ModuleGraph; rd: PRodReader) =
   for m in items(rd.methods): methodDef(graph, m, true)
 
-proc isImportSystemStmt(n: PNode): bool =
-  if magicsys.systemModule == nil: return false
+proc isImportSystemStmt(g: ModuleGraph; n: PNode): bool =
+  if g.systemModule == nil: return false
   case n.kind
   of nkImportStmt:
     for x in n:
       if x.kind == nkIdent:
-        let f = checkModuleName(x, false)
-        if f == magicsys.systemModule.info.fileIndex:
+        let f = checkModuleName(g.config, x, false)
+        if f == g.systemModule.info.fileIndex:
           return true
   of nkImportExceptStmt, nkFromStmt:
     if n[0].kind == nkIdent:
-      let f = checkModuleName(n[0], false)
-      if f == magicsys.systemModule.info.fileIndex:
+      let f = checkModuleName(g.config, n[0], false)
+      if f == g.systemModule.info.fileIndex:
         return true
   else: discard
 
 proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
   if n.kind == nkDefer:
-    localError(n.info, "defer statement not supported at top level")
-  if c.topStmts == 0 and not isImportSystemStmt(n):
+    localError(c.config, n.info, "defer statement not supported at top level")
+  if c.topStmts == 0 and not isImportSystemStmt(c.graph, n):
     if sfSystemModule notin c.module.flags and
         n.kind notin {nkEmpty, nkCommentStmt}:
-      c.importTable.addSym magicsys.systemModule # import the "System" identifier
-      importAllSymbols(c, magicsys.systemModule)
+      c.importTable.addSym c.graph.systemModule # import the "System" identifier
+      importAllSymbols(c, c.graph.systemModule)
       inc c.topStmts
   else:
     inc c.topStmts
@@ -556,11 +562,11 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
         if result.kind != nkEmpty: addSon(a, result)
         result = a
   result = hloStmt(c, result)
-  if gCmd == cmdInteractive and not isEmptyType(result.typ):
+  if c.config.cmd == cmdInteractive and not isEmptyType(result.typ):
     result = buildEchoStmt(c, result)
-  if gCmd == cmdIdeTools:
+  if c.config.cmd == cmdIdeTools:
     appendToModule(c.module, result)
-  result = transformStmt(c.module, result)
+  result = transformStmt(c.graph, c.module, result)
 
 proc recoverContext(c: PContext) =
   # clean up in case of a semantic error: We clean up the stacks, etc. This is
@@ -573,7 +579,7 @@ proc recoverContext(c: PContext) =
 proc myProcess(context: PPassContext, n: PNode): PNode =
   var c = PContext(context)
   # no need for an expensive 'try' if we stop after the first error anyway:
-  if msgs.gErrorMax <= 1:
+  if c.config.errorMax <= 1:
     result = semStmtAndGenerateGenerics(c, n)
   else:
     let oldContextLen = msgs.getInfoContextLen()
@@ -589,16 +595,16 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
         result = nil
       else:
         result = ast.emptyNode
-      #if gCmd == cmdIdeTools: findSuggest(c, n)
+      #if c.config.cmd == cmdIdeTools: findSuggest(c, n)
   rod.storeNode(c.module, result)
 
 proc testExamples(c: PContext) =
   let inp = toFullPath(c.module.info)
   let outp = inp.changeFileExt"" & "_examples.nim"
   renderModule(c.runnableExamples, inp, outp)
-  let backend = if isDefined("js"): "js"
-                elif isDefined("cpp"): "cpp"
-                elif isDefined("objc"): "objc"
+  let backend = if isDefined(c.config, "js"): "js"
+                elif isDefined(c.config, "cpp"): "cpp"
+                elif isDefined(c.config, "objc"): "objc"
                 else: "c"
   if os.execShellCmd("nim " & backend & " -r " & outp) != 0:
     quit "[Examples] failed"
@@ -606,13 +612,13 @@ proc testExamples(c: PContext) =
 
 proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode =
   var c = PContext(context)
-  if gCmd == cmdIdeTools and not c.suggestionsMade:
+  if c.config.cmd == cmdIdeTools and not c.suggestionsMade:
     suggestSentinel(c)
   closeScope(c)         # close module's scope
   rawCloseScope(c)      # imported symbols; don't check for unused ones!
   result = newNode(nkStmtList)
   if n != nil:
-    internalError(n.info, "n is not nil") #result := n;
+    internalError(c.config, n.info, "n is not nil") #result := n;
   addCodeForGenerics(c, result)
   if c.module.ast != nil:
     result.add(c.module.ast)
diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim
index 5c7b91f6d..f0fde195c 100644
--- a/compiler/semasgn.nim
+++ b/compiler/semasgn.nim
@@ -33,7 +33,7 @@ proc at(a, i: PNode, elemType: PType): PNode =
 
 proc liftBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) =
   for i in 0 ..< t.len:
-    let lit = lowerings.newIntLit(i)
+    let lit = lowerings.newIntLit(c.c.graph, x.info, i)
     liftBodyAux(c, t.sons[i], body, x.at(lit, t.sons[i]), y.at(lit, t.sons[i]))
 
 proc dotField(x: PNode, f: PSym): PNode =
@@ -66,15 +66,15 @@ proc liftBodyObj(c: var TLiftCtx; n, body, x, y: PNode) =
       liftBodyObj(c, n[i].lastSon, branch.sons[L-1], x, y)
       caseStmt.add(branch)
     body.add(caseStmt)
-    localError(c.info, "cannot lift assignment operator to 'case' object")
+    localError(c.c.config, c.info, "cannot lift assignment operator to 'case' object")
   of nkRecList:
     for t in items(n): liftBodyObj(c, t, body, x, y)
   else:
-    illFormedAstLocal(n)
+    illFormedAstLocal(n, c.c.config)
 
 proc genAddr(c: PContext; x: PNode): PNode =
   if x.kind == nkHiddenDeref:
-    checkSonsLen(x, 1)
+    checkSonsLen(x, 1, c.config)
     result = x.sons[0]
   else:
     result = newNodeIT(nkHiddenAddr, x.info, makeVarType(c, x.typ))
@@ -82,7 +82,7 @@ proc genAddr(c: PContext; x: PNode): PNode =
 
 proc newAsgnCall(c: PContext; op: PSym; x, y: PNode): PNode =
   if sfError in op.flags:
-    localError(x.info, errWrongSymbolX, op.name.s)
+    localError(c.config, x.info, "usage of '$1' is a user-defined error" % op.name.s)
   result = newNodeI(nkCall, x.info)
   result.add newSymNode(op)
   result.add genAddr(c, x)
@@ -124,7 +124,7 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
       op = field
       if op == nil:
         op = liftBody(c.c, t, c.kind, c.info)
-    markUsed(c.info, op, c.c.graph.usageSym)
+    markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
     styleCheckUse(c.info, op)
     body.add newAsgnCall(c.c, op, x, y)
     result = true
@@ -134,7 +134,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
   of attachedDestructor:
     let op = t.destructor
     if op != nil:
-      markUsed(c.info, op, c.c.graph.usageSym)
+      markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
       styleCheckUse(c.info, op)
       body.add destructorCall(c.c, op, x)
       result = true
@@ -145,7 +145,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
   of attachedDeepCopy:
     let op = t.deepCopy
     if op != nil:
-      markUsed(c.info, op, c.c.graph.usageSym)
+      markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
       styleCheckUse(c.info, op)
       body.add newDeepCopyCall(op, x, y)
       result = true
@@ -163,37 +163,37 @@ proc addVar(father, v, value: PNode) =
 
 proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
   var temp = newSym(skTemp, getIdent(lowerings.genPrefix), c.fn, c.info)
-  temp.typ = getSysType(tyInt)
+  temp.typ = getSysType(c.c.graph, body.info, tyInt)
   incl(temp.flags, sfFromGeneric)
 
   var v = newNodeI(nkVarSection, c.info)
   result = newSymNode(temp)
-  v.addVar(result, lowerings.newIntLit(first))
+  v.addVar(result, lowerings.newIntLit(c.c.graph, body.info, first))
   body.add v
 
-proc genBuiltin(magic: TMagic; name: string; i: PNode): PNode =
+proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode =
   result = newNodeI(nkCall, i.info)
-  result.add createMagic(name, magic).newSymNode
+  result.add createMagic(g, name, magic).newSymNode
   result.add i
 
 proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode =
   result = newNodeI(nkWhileStmt, c.info, 2)
-  let cmp = genBuiltin(mLeI, "<=", i)
-  cmp.add genHigh(dest)
-  cmp.typ = getSysType(tyBool)
+  let cmp = genBuiltin(c.c.graph, mLeI, "<=", i)
+  cmp.add genHigh(c.c.graph, dest)
+  cmp.typ = getSysType(c.c.graph, c.info, tyBool)
   result.sons[0] = cmp
   result.sons[1] = newNodeI(nkStmtList, c.info)
 
-proc addIncStmt(body, i: PNode) =
-  let incCall = genBuiltin(mInc, "inc", i)
-  incCall.add lowerings.newIntLit(1)
+proc addIncStmt(c: var TLiftCtx; body, i: PNode) =
+  let incCall = genBuiltin(c.c.graph, mInc, "inc", i)
+  incCall.add lowerings.newIntLit(c.c.graph, c.info, 1)
   body.add incCall
 
 proc newSeqCall(c: PContext; x, y: PNode): PNode =
   # don't call genAddr(c, x) here:
-  result = genBuiltin(mNewSeq, "newSeq", x)
-  let lenCall = genBuiltin(mLengthSeq, "len", y)
-  lenCall.typ = getSysType(tyInt)
+  result = genBuiltin(c.graph, mNewSeq, "newSeq", x)
+  let lenCall = genBuiltin(c.graph, mLengthSeq, "len", y)
+  lenCall.typ = getSysType(c.graph, x.info, tyInt)
   result.add lenCall
 
 proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
@@ -212,7 +212,7 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
       let elemType = t.lastSon
       liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType),
                                                   y.at(i, elemType))
-      addIncStmt(whileLoop.sons[1], i)
+      addIncStmt(c, whileLoop.sons[1], i)
       body.add whileLoop
     else:
       defaultOp(c, t, body, x, y)
@@ -231,20 +231,20 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
       # have to go through some indirection; we delegate this to the codegen:
       let call = newNodeI(nkCall, c.info, 2)
       call.typ = t
-      call.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy))
+      call.sons[0] = newSymNode(createMagic(c.c.graph, "deepCopy", mDeepCopy))
       call.sons[1] = y
       body.add newAsgnStmt(x, call)
   of tyVarargs, tyOpenArray:
-    localError(c.info, errGenerated, "cannot copy openArray")
+    localError(c.c.config, c.info, "cannot copy openArray")
   of tyFromExpr, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
      tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything,
      tyGenericParam, tyGenericBody, tyNil, tyExpr, tyStmt,
      tyTypeDesc, tyGenericInvocation, tyForward:
-    internalError(c.info, "assignment requested for type: " & typeToString(t))
+    internalError(c.c.config, c.info, "assignment requested for type: " & typeToString(t))
   of tyOrdinal, tyRange, tyInferred,
      tyGenericInst, tyStatic, tyVar, tyLent, tyAlias, tySink:
     liftBodyAux(c, lastSon(t), body, x, y)
-  of tyUnused, tyOptAsRef: internalError("liftBodyAux")
+  of tyUnused, tyOptAsRef: internalError(c.c.config, "liftBodyAux")
 
 proc newProcType(info: TLineInfo; owner: PSym): PType =
   result = newType(tyProc, owner)
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index aa53fda3b..e9a31d3d6 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -202,24 +202,31 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
 
   result = (prefer, candidates)
 
+const
+  errTypeMismatch = "type mismatch: got <"
+  errButExpected = "but expected one of: "
+  errUndeclaredField = "undeclared field: '$1'"
+  errUndeclaredRoutine = "attempting to call undeclared routine: '$1'"
+  errAmbiguousCallXYZ = "ambiguous call; both $1 and $2 match for: $3"
+
 proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
   # Gives a detailed error message; this is separated from semOverloadedCall,
   # as semOverlodedCall is already pretty slow (and we need this information
   # only in case of an error).
   if errorOutputs == {}:
     # fail fast:
-    globalError(n.info, errTypeMismatch, "")
+    globalError(c.config, n.info, "type mismatch")
   if errors.len == 0:
-    localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
+    localError(c.config, n.info, "expression '$1' cannot be called" % n[0].renderTree)
     return
 
   let (prefer, candidates) = presentFailedCandidates(c, n, errors)
-  var result = msgKindToString(errTypeMismatch)
+  var result = errTypeMismatch
   add(result, describeArgs(c, n, 1, prefer))
   add(result, '>')
   if candidates != "":
-    add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
-  localError(n.info, errGenerated, result & "\nexpression: " & $n)
+    add(result, "\n" & errButExpected & "\n" & candidates)
+  localError(c.config, n.info, result & "\nexpression: " & $n)
 
 proc bracketNotFoundError(c: PContext; n: PNode) =
   var errors: CandidateErrors = @[]
@@ -234,7 +241,7 @@ proc bracketNotFoundError(c: PContext; n: PNode) =
                                 enabled: false))
     symx = nextOverloadIter(o, c, headSymbol)
   if errors.len == 0:
-    localError(n.info, "could not resolve: " & $n)
+    localError(c.config, n.info, "could not resolve: " & $n)
   else:
     notFoundError(c, n, errors)
 
@@ -277,7 +284,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
       else: return
 
     if nfDotField in n.flags:
-      internalAssert f.kind == nkIdent and n.sonsLen >= 2
+      internalAssert c.config, f.kind == nkIdent and n.len >= 2
 
       # leave the op head symbol empty,
       # we are going to try multiple variants
@@ -306,13 +313,13 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
 
     if overloadsState == csEmpty and result.state == csEmpty:
       if nfDotField in n.flags and nfExplicitCall notin n.flags:
-        localError(n.info, errUndeclaredField, considerQuotedIdent(f, n).s)
+        localError(c.config, n.info, errUndeclaredField % considerQuotedIdent(c.config, f, n).s)
       else:
-        localError(n.info, errUndeclaredRoutine, considerQuotedIdent(f, n).s)
+        localError(c.config, n.info, errUndeclaredRoutine % considerQuotedIdent(c.config, f, n).s)
       return
     elif result.state != csMatch:
       if nfExprCall in n.flags:
-        localError(n.info, errExprXCannotBeCalled,
+        localError(c.config, n.info, "expression '$1' cannot be called" %
                    renderTree(n, {renderNoComments}))
       else:
         if {nfDotField, nfDotSetter} * n.flags != {}:
@@ -322,13 +329,13 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
       return
   if alt.state == csMatch and cmpCandidates(result, alt) == 0 and
       not sameMethodDispatcher(result.calleeSym, alt.calleeSym):
-    internalAssert result.state == csMatch
+    internalAssert c.config, result.state == csMatch
     #writeMatches(result)
     #writeMatches(alt)
     if errorOutputs == {}:
       # quick error message for performance of 'compiles' built-in:
-      globalError(n.info, errGenerated, "ambiguous call")
-    elif gErrorCounter == 0:
+      globalError(c.config, n.info, errGenerated, "ambiguous call")
+    elif c.config.errorCounter == 0:
       # don't cascade errors
       var args = "("
       for i in countup(1, sonsLen(n) - 1):
@@ -336,7 +343,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
         add(args, typeToString(n.sons[i].typ))
       add(args, ")")
 
-      localError(n.info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
+      localError(c.config, n.info, errAmbiguousCallXYZ % [
         getProcHeader(result.calleeSym), getProcHeader(alt.calleeSym),
         args])
 
@@ -377,7 +384,7 @@ proc inferWithMetatype(c: PContext, formal: PType,
     result.typ = generateTypeInstance(c, m.bindings, arg.info,
                                       formal.skipTypes({tyCompositeTypeClass}))
   else:
-    typeMismatch(arg.info, formal, arg.typ)
+    typeMismatch(c.config, arg.info, formal, arg.typ)
     # error correction:
     result = copyTree(arg)
     result.typ = formal
@@ -385,7 +392,7 @@ proc inferWithMetatype(c: PContext, formal: PType,
 proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
   assert x.state == csMatch
   var finalCallee = x.calleeSym
-  markUsed(n.sons[0].info, finalCallee, c.graph.usageSym)
+  markUsed(c.config, n.sons[0].info, finalCallee, c.graph.usageSym)
   styleCheckUse(n.sons[0].info, finalCallee)
   assert finalCallee.ast != nil
   if x.hasFauxMatch:
@@ -411,7 +418,7 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
         of skType:
           x.call.add newSymNode(s, n.info)
         else:
-          internalAssert false
+          internalAssert c.config, false
 
   result = x.call
   instGenericConvertersSons(c, result, x)
@@ -435,7 +442,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
     # this may be triggered, when the explain pragma is used
     if errors.len > 0:
       let (_, candidates) = presentFailedCandidates(c, n, errors)
-      message(n.info, hintUserRaw,
+      message(c.config, n.info, hintUserRaw,
               "Non-matching candidates for " & renderTree(n) & "\n" &
               candidates)
     result = semResolvedCall(c, n, r)
@@ -468,8 +475,8 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
     else:
       notFoundError(c, n, errors)
 
-proc explicitGenericInstError(n: PNode): PNode =
-  localError(n.info, errCannotInstantiateX, renderTree(n))
+proc explicitGenericInstError(c: PContext; n: PNode): PNode =
+  localError(c.config, n.info, errCannotInstantiateX % renderTree(n))
   result = n
 
 proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
@@ -484,7 +491,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
     if tm in {isNone, isConvertible}: return nil
   var newInst = generateInstance(c, s, m.bindings, n.info)
   newInst.typ.flags.excl tfUnresolved
-  markUsed(n.info, s, c.graph.usageSym)
+  markUsed(c.config, n.info, s, c.graph.usageSym)
   styleCheckUse(n.info, s)
   result = newSymNode(newInst, n.info)
 
@@ -500,11 +507,11 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
     # number of generic type parameters:
     if safeLen(s.ast.sons[genericParamsPos]) != n.len-1:
       let expected = safeLen(s.ast.sons[genericParamsPos])
-      localError(n.info, errGenerated, "cannot instantiate: " & renderTree(n) &
-         "; got " & $(n.len-1) & " type(s) but expected " & $expected)
+      localError(c.config, n.info, errGenerated, "cannot instantiate: '" & renderTree(n) &
+         "'; got " & $(n.len-1) & " type(s) but expected " & $expected)
       return n
     result = explicitGenericSym(c, n, s)
-    if result == nil: result = explicitGenericInstError(n)
+    if result == nil: result = explicitGenericInstError(c, n)
   elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
     # choose the generic proc with the proper number of type parameters.
     # XXX I think this could be improved by reusing sigmatch.paramTypesMatch.
@@ -522,10 +529,10 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
     # get rid of nkClosedSymChoice if not ambiguous:
     if result.len == 1 and a.kind == nkClosedSymChoice:
       result = result[0]
-    elif result.len == 0: result = explicitGenericInstError(n)
-    # candidateCount != 1: return explicitGenericInstError(n)
+    elif result.len == 0: result = explicitGenericInstError(c, n)
+    # candidateCount != 1: return explicitGenericInstError(c, n)
   else:
-    result = explicitGenericInstError(n)
+    result = explicitGenericInstError(c, n)
 
 proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
   # Searchs for the fn in the symbol table. If the parameter lists are suitable
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 62be471f7..12ac19ca3 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -14,7 +14,7 @@ import
   wordrecg,
   ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math,
   magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef,
-  modulegraphs
+  modulegraphs, configuration
 
 type
   TOptionEntry* = object      # entries to put on a stack for pragma parsing
@@ -140,6 +140,8 @@ type
       # would otherwise fail.
     runnableExamples*: PNode
 
+template config*(c: PContext): ConfigRef = c.graph.config
+
 proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
   result.genericSym = s
   result.inst = inst
@@ -165,7 +167,7 @@ proc pushOwner*(c: PContext; owner: PSym) =
 proc popOwner*(c: PContext) =
   var length = len(c.graph.owners)
   if length > 0: setLen(c.graph.owners, length - 1)
-  else: internalError("popOwner")
+  else: internalError(c.config, "popOwner")
 
 proc lastOptionEntry*(c: PContext): POptionEntry =
   result = c.optionStack[^1]
@@ -201,19 +203,19 @@ proc considerGenSyms*(c: PContext; n: PNode) =
     for i in 0..<n.safeLen:
       considerGenSyms(c, n.sons[i])
 
-proc newOptionEntry*(): POptionEntry =
+proc newOptionEntry*(conf: ConfigRef): POptionEntry =
   new(result)
-  result.options = gOptions
+  result.options = conf.options
   result.defaultCC = ccDefault
   result.dynlib = nil
-  result.notes = gNotes
+  result.notes = conf.notes
 
 proc newContext*(graph: ModuleGraph; module: PSym; cache: IdentCache): PContext =
   new(result)
   result.ambiguousSymbols = initIntSet()
   result.optionStack = @[]
   result.libs = @[]
-  result.optionStack.add(newOptionEntry())
+  result.optionStack.add(newOptionEntry(graph.config))
   result.module = module
   result.friendModules = @[module]
   result.converters = @[]
@@ -256,7 +258,7 @@ proc newTypeS*(kind: TTypeKind, c: PContext): PType =
 
 proc makePtrType*(c: PContext, baseType: PType): PType =
   result = newTypeS(tyPtr, c)
-  addSonSkipIntLit(result, baseType.assertNotNil)
+  addSonSkipIntLit(result, baseType)
 
 proc makeTypeWithModifier*(c: PContext,
                            modifier: TTypeKind,
@@ -267,25 +269,26 @@ proc makeTypeWithModifier*(c: PContext,
     result = baseType
   else:
     result = newTypeS(modifier, c)
-    addSonSkipIntLit(result, baseType.assertNotNil)
+    addSonSkipIntLit(result, baseType)
 
 proc makeVarType*(c: PContext, baseType: PType; kind = tyVar): PType =
   if baseType.kind == kind:
     result = baseType
   else:
     result = newTypeS(kind, c)
-    addSonSkipIntLit(result, baseType.assertNotNil)
+    addSonSkipIntLit(result, baseType)
 
 proc makeTypeDesc*(c: PContext, typ: PType): PType =
   if typ.kind == tyTypeDesc:
     result = typ
   else:
     result = newTypeS(tyTypeDesc, c)
-    result.addSonSkipIntLit(typ.assertNotNil)
+    result.addSonSkipIntLit(typ)
 
 proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
   let typedesc = makeTypeDesc(c, typ)
-  let sym = newSym(skType, c.cache.idAnon, getCurrOwner(c), info).linkTo(typedesc)
+  let sym = newSym(skType, c.cache.idAnon, getCurrOwner(c), info,
+                   c.config.options).linkTo(typedesc)
   return newSymNode(sym, info)
 
 proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
@@ -340,21 +343,20 @@ proc makeNotType*(c: PContext, t1: PType): PType =
   result.flags.incl(t1.flags * {tfHasStatic})
   result.flags.incl tfHasMeta
 
-proc nMinusOne*(n: PNode): PNode =
+proc nMinusOne(c: PContext; n: PNode): PNode =
   result = newNode(nkCall, n.info, @[
-    newSymNode(getSysMagic("pred", mPred)),
-    n])
+    newSymNode(getSysMagic(c.graph, n.info, "pred", mPred)), n])
 
 # Remember to fix the procs below this one when you make changes!
 proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType =
-  let intType = getSysType(tyInt)
+  let intType = getSysType(c.graph, n.info, tyInt)
   result = newTypeS(tyRange, c)
   result.sons = @[intType]
   if n.typ != nil and n.typ.n == nil:
     result.flags.incl tfUnresolved
   result.n = newNode(nkRange, n.info, @[
     newIntTypeNode(nkIntLit, 0, intType),
-    makeStaticExpr(c, n.nMinusOne)])
+    makeStaticExpr(c, nMinusOne(c, n))])
 
 template rangeHasUnresolvedStatic*(t: PType): bool =
   tfUnresolved in t.flags
@@ -373,7 +375,8 @@ proc fillTypeS*(dest: PType, kind: TTypeKind, c: PContext) =
   dest.size = - 1
 
 proc makeRangeType*(c: PContext; first, last: BiggestInt;
-                    info: TLineInfo; intType = getSysType(tyInt)): PType =
+                    info: TLineInfo; intType: PType = nil): PType =
+  let intType = if intType != nil: intType else: getSysType(c.graph, info, tyInt)
   var n = newNodeI(nkRange, info)
   addSon(n, newIntTypeNode(nkIntLit, first, intType))
   addSon(n, newIntTypeNode(nkIntLit, last, intType))
@@ -386,17 +389,17 @@ proc markIndirect*(c: PContext, s: PSym) {.inline.} =
     incl(s.flags, sfAddrTaken)
     # XXX add to 'c' for global analysis
 
-proc illFormedAst*(n: PNode) =
-  globalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
+proc illFormedAst*(n: PNode; conf: ConfigRef) =
+  globalError(conf, n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
 
-proc illFormedAstLocal*(n: PNode) =
-  localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
+proc illFormedAstLocal*(n: PNode; conf: ConfigRef) =
+  localError(conf, n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
 
-proc checkSonsLen*(n: PNode, length: int) =
-  if sonsLen(n) != length: illFormedAst(n)
+proc checkSonsLen*(n: PNode, length: int; conf: ConfigRef) =
+  if sonsLen(n) != length: illFormedAst(n, conf)
 
-proc checkMinSonsLen*(n: PNode, length: int) =
-  if sonsLen(n) < length: illFormedAst(n)
+proc checkMinSonsLen*(n: PNode, length: int; conf: ConfigRef) =
+  if sonsLen(n) < length: illFormedAst(n, conf)
 
 proc isTopLevel*(c: PContext): bool {.inline.} =
   result = c.currentScope.depthLevel <= 2
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 79010bfde..92b9c365a 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -10,12 +10,24 @@
 # this module does the semantic checking for expressions
 # included from sem.nim
 
+const
+  errExprXHasNoType = "expression '$1' has no type (or is ambiguous)"
+  errXExpectsTypeOrValue = "'$1' expects a type or value"
+  errVarForOutParamNeededX = "for a 'var' type a variable needs to be passed; but '$1' is immutable"
+  errXStackEscape = "address of '$1' may not escape its stack frame"
+  errExprHasNoAddress = "expression has no address; maybe use 'unsafeAddr'"
+  errCannotInterpretNodeX = "cannot evaluate '$1'"
+  errNamedExprExpected = "named expression expected"
+  errNamedExprNotAllowed = "named expression not allowed here"
+  errFieldInitTwice = "field initialized twice: '$1'"
+  errUndeclaredFieldX = "undeclared field: '$1'"
+
 proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
                      flags: TExprFlags = {}): PNode =
-  markUsed(n.info, s, c.graph.usageSym)
+  markUsed(c.config, n.info, s, c.graph.usageSym)
   styleCheckUse(n.info, s)
   pushInfoContext(n.info)
-  result = evalTemplate(n, s, getCurrOwner(c), efFromHlo in flags)
+  result = evalTemplate(n, s, getCurrOwner(c), c.config, efFromHlo in flags)
   if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags)
   popInfoContext()
 
@@ -31,12 +43,12 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   if result.typ != nil:
     # XXX tyGenericInst here?
     if result.typ.kind == tyProc and tfUnresolved in result.typ.flags:
-      localError(n.info, errProcHasNoConcreteType, n.renderTree)
+      localError(c.config, n.info, errProcHasNoConcreteType % n.renderTree)
     if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
   elif {efWantStmt, efAllowStmt} * flags != {}:
     result.typ = newTypeS(tyVoid, c)
   else:
-    localError(n.info, errExprXHasNoType,
+    localError(c.config, n.info, errExprXHasNoType %
                renderTree(result, {renderNoComments}))
     result.typ = errorType(c)
 
@@ -47,7 +59,7 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     #raiseRecoverableError("")
     result = errorNode(c, n)
   if result.typ == nil or result.typ == enforceVoidContext:
-    localError(n.info, errExprXHasNoType,
+    localError(c.config, n.info, errExprXHasNoType %
                 renderTree(result, {renderNoComments}))
     result.typ = errorType(c)
   else:
@@ -59,17 +71,17 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     # do not produce another redundant error message:
     result = errorNode(c, n)
   if result.typ == nil:
-    localError(n.info, errExprXHasNoType,
+    localError(c.config, n.info, errExprXHasNoType %
                renderTree(result, {renderNoComments}))
     result.typ = errorType(c)
 
 proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
   result = symChoice(c, n, s, scClosed)
 
-proc inlineConst(n: PNode, s: PSym): PNode {.inline.} =
+proc inlineConst(c: PContext, n: PNode, s: PSym): PNode {.inline.} =
   result = copyTree(s.ast)
   if result.isNil:
-    localError(n.info, "constant of type '" & typeToString(s.typ) & "' has no value")
+    localError(c.config, n.info, "constant of type '" & typeToString(s.typ) & "' has no value")
     result = newSymNode(s)
   else:
     result.typ = s.typ
@@ -172,7 +184,7 @@ proc maybeLiftType(t: var PType, c: PContext, info: TLineInfo) =
 
 proc semConv(c: PContext, n: PNode): PNode =
   if sonsLen(n) != 2:
-    localError(n.info, errConvNeedsOneArg)
+    localError(c.config, n.info, "a type conversion takes exactly one argument")
     return n
 
   result = newNodeI(nkConv, n.info)
@@ -192,7 +204,7 @@ proc semConv(c: PContext, n: PNode): PNode =
   # special case to make MyObject(x = 3) produce a nicer error message:
   if n[1].kind == nkExprEqExpr and
       targetType.skipTypes(abstractPtrs).kind == tyObject:
-    localError(n.info, "object contruction uses ':', not '='")
+    localError(c.config, n.info, "object contruction uses ':', not '='")
   var op = semExprWithType(c, n.sons[1])
   if targetType.isMetaType:
     let final = inferWithMetatype(c, targetType, op, true)
@@ -215,18 +227,18 @@ proc semConv(c: PContext, n: PNode): PNode =
       elif op.kind in {nkPar, nkTupleConstr} and targetType.kind == tyTuple:
         op = fitNode(c, targetType, op, result.info)
     of convNotNeedeed:
-      message(n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString)
+      message(c.config, n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString)
     of convNotLegal:
       result = fitNode(c, result.typ, result.sons[1], result.info)
       if result == nil:
-        localError(n.info, errGenerated, msgKindToString(errIllegalConvFromXtoY)%
+        localError(c.config, n.info, "illegal conversion from '$1' to '$2'" %
           [op.typ.typeToString, result.typ.typeToString])
   else:
     for i in countup(0, sonsLen(op) - 1):
       let it = op.sons[i]
       let status = checkConvertible(c, result.typ, it.typ)
       if status in {convOK, convNotNeedeed}:
-        markUsed(n.info, it.sym, c.graph.usageSym)
+        markUsed(c.config, n.info, it.sym, c.graph.usageSym)
         styleCheckUse(n.info, it.sym)
         markIndirect(c, it.sym)
         return it
@@ -234,16 +246,16 @@ proc semConv(c: PContext, n: PNode): PNode =
 
 proc semCast(c: PContext, n: PNode): PNode =
   ## Semantically analyze a casting ("cast[type](param)")
-  checkSonsLen(n, 2)
+  checkSonsLen(n, 2, c.config)
   let targetType = semTypeNode(c, n.sons[0], nil)
   let castedExpr = semExprWithType(c, n.sons[1])
   if tfHasMeta in targetType.flags:
-    localError(n.sons[0].info, errCastToANonConcreteType, $targetType)
+    localError(c.config, n.sons[0].info, "cannot cast to a non concrete type: '$1'" % $targetType)
   if not isCastable(targetType, castedExpr.typ):
     let tar = $targetType
     let alt = typeToString(targetType, preferDesc)
     let msg = if tar != alt: tar & "=" & alt else: tar
-    localError(n.info, errExprCannotBeCastToX, msg)
+    localError(c.config, n.info, "expression cannot be cast to " & msg)
   result = newNodeI(nkCast, n.info)
   result.typ = targetType
   addSon(result, copyTree(n.sons[0]))
@@ -253,13 +265,13 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
   const
     opToStr: array[mLow..mHigh, string] = ["low", "high"]
   if sonsLen(n) != 2:
-    localError(n.info, errXExpectsTypeOrValue, opToStr[m])
+    localError(c.config, n.info, errXExpectsTypeOrValue % opToStr[m])
   else:
     n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
     var typ = skipTypes(n.sons[1].typ, abstractVarRange + {tyTypeDesc})
     case typ.kind
     of tySequence, tyString, tyCString, tyOpenArray, tyVarargs:
-      n.typ = getSysType(tyInt)
+      n.typ = getSysType(c.graph, n.info, tyInt)
     of tyArray:
       n.typ = typ.sons[0] # indextype
     of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32:
@@ -271,20 +283,20 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
       # that could easily turn into an infinite recursion in semtypinst
       n.typ = makeTypeFromExpr(c, n.copyTree)
     else:
-      localError(n.info, errInvalidArgForX, opToStr[m])
+      localError(c.config, n.info, "invalid argument for: " & opToStr[m])
   result = n
 
 proc semSizeof(c: PContext, n: PNode): PNode =
   if sonsLen(n) != 2:
-    localError(n.info, errXExpectsTypeOrValue, "sizeof")
+    localError(c.config, n.info, errXExpectsTypeOrValue % "sizeof")
   else:
     n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
     #restoreOldStyleType(n.sons[1])
-  n.typ = getSysType(tyInt)
+  n.typ = getSysType(c.graph, n.info, tyInt)
   result = n
 
 proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
-  internalAssert n.sonsLen == 3 and
+  internalAssert c.config, n.sonsLen == 3 and
     n[1].typ != nil and n[1].typ.kind == tyTypeDesc and
     n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
 
@@ -315,10 +327,10 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
 
 proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
   if sonsLen(n) != 3:
-    localError(n.info, errXExpectsTwoArguments, "is")
+    localError(c.config, n.info, "'is' operator takes 2 arguments")
 
   result = n
-  n.typ = getSysType(tyBool)
+  n.typ = getSysType(c.graph, n.info, tyBool)
 
   n.sons[1] = semExprWithType(c, n[1], {efDetermineType, efWantIterator})
   if n[2].kind notin {nkStrLit..nkTripleStrLit}:
@@ -340,8 +352,8 @@ proc semOpAux(c: PContext, n: PNode) =
   for i in countup(1, n.sonsLen-1):
     var a = n.sons[i]
     if a.kind == nkExprEqExpr and sonsLen(a) == 2:
-      var info = a.sons[0].info
-      a.sons[0] = newIdentNode(considerQuotedIdent(a.sons[0], a), info)
+      let info = a.sons[0].info
+      a.sons[0] = newIdentNode(considerQuotedIdent(c.config, a.sons[0], a), info)
       a.sons[1] = semExprWithType(c, a.sons[1], flags)
       a.typ = a.sons[1].typ
     else:
@@ -358,34 +370,34 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode =
     for i in countup(0, sonsLen(n) - 1): addSon(result, n.sons[i])
     result = semExpr(c, result)
 
-proc changeType(n: PNode, newType: PType, check: bool) =
+proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
   case n.kind
   of nkCurly, nkBracket:
     for i in countup(0, sonsLen(n) - 1):
-      changeType(n.sons[i], elemType(newType), check)
+      changeType(c, n.sons[i], elemType(newType), check)
   of nkPar, nkTupleConstr:
     let tup = newType.skipTypes({tyGenericInst, tyAlias, tySink})
     if tup.kind != tyTuple:
       if tup.kind == tyObject: return
-      globalError(n.info, "no tuple type for constructor")
+      globalError(c.config, n.info, "no tuple type for constructor")
     elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr:
       # named tuple?
       for i in countup(0, sonsLen(n) - 1):
         var m = n.sons[i].sons[0]
         if m.kind != nkSym:
-          globalError(m.info, "invalid tuple constructor")
+          globalError(c.config, m.info, "invalid tuple constructor")
           return
         if tup.n != nil:
           var f = getSymFromList(tup.n, m.sym.name)
           if f == nil:
-            globalError(m.info, "unknown identifier: " & m.sym.name.s)
+            globalError(c.config, m.info, "unknown identifier: " & m.sym.name.s)
             return
-          changeType(n.sons[i].sons[1], f.typ, check)
+          changeType(c, n.sons[i].sons[1], f.typ, check)
         else:
-          changeType(n.sons[i].sons[1], tup.sons[i], check)
+          changeType(c, n.sons[i].sons[1], tup.sons[i], check)
     else:
       for i in countup(0, sonsLen(n) - 1):
-        changeType(n.sons[i], tup.sons[i], check)
+        changeType(c, n.sons[i], tup.sons[i], check)
         when false:
           var m = n.sons[i]
           var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
@@ -396,7 +408,7 @@ proc changeType(n: PNode, newType: PType, check: bool) =
     if check and n.kind != nkUInt64Lit:
       let value = n.intVal
       if value < firstOrd(newType) or value > lastOrd(newType):
-        localError(n.info, errGenerated, "cannot convert " & $value &
+        localError(c.config, n.info, "cannot convert " & $value &
                                          " to " & typeToString(newType))
   else: discard
   n.typ = newType
@@ -421,7 +433,7 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
   else:
     var x = n.sons[0]
     var lastIndex: BiggestInt = 0
-    var indexType = getSysType(tyInt)
+    var indexType = getSysType(c.graph, n.info, tyInt)
     if x.kind == nkExprColonExpr and sonsLen(x) == 2:
       var idx = semConstExpr(c, x.sons[0])
       lastIndex = getOrdValue(idx)
@@ -438,7 +450,7 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
         var idx = semConstExpr(c, x.sons[0])
         idx = fitNode(c, indexType, idx, x.info)
         if lastIndex+1 != getOrdValue(idx):
-          localError(x.info, errInvalidOrderInArrayConstructor)
+          localError(c.config, x.info, "invalid order in array constructor")
         x = x.sons[1]
 
       let xx = semExprWithType(c, x, flags*{efAllowDestructor})
@@ -462,22 +474,22 @@ proc fixAbstractType(c: PContext, n: PNode) =
             {tyNil, tyTuple, tySet} or it[1].isArrayConstr:
         var s = skipTypes(it.typ, abstractVar)
         if s.kind != tyExpr:
-          changeType(it.sons[1], s, check=true)
+          changeType(c, it.sons[1], s, check=true)
         n.sons[i] = it.sons[1]
 
 proc isAssignable(c: PContext, n: PNode; isUnsafeAddr=false): TAssignableResult =
   result = parampatterns.isAssignable(c.p.owner, n, isUnsafeAddr)
 
 proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
-  if n.kind == nkHiddenDeref and not (gCmd == cmdCompileToCpp or
+  if n.kind == nkHiddenDeref and not (c.config.cmd == cmdCompileToCpp or
                                       sfCompileToCpp in c.module.flags):
-    checkSonsLen(n, 1)
+    checkSonsLen(n, 1, c.config)
     result = n.sons[0]
   else:
     result = newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ))
     addSon(result, n)
     if isAssignable(c, n) notin {arLValue, arLocalLValue}:
-      localError(n.info, errVarForOutParamNeededX, renderNotLValue(n))
+      localError(c.config, n.info, errVarForOutParamNeededX % renderNotLValue(n))
 
 proc analyseIfAddressTaken(c: PContext, n: PNode): PNode =
   result = n
@@ -489,15 +501,15 @@ proc analyseIfAddressTaken(c: PContext, n: PNode): PNode =
       incl(n.sym.flags, sfAddrTaken)
       result = newHiddenAddrTaken(c, n)
   of nkDotExpr:
-    checkSonsLen(n, 2)
+    checkSonsLen(n, 2, c.config)
     if n.sons[1].kind != nkSym:
-      internalError(n.info, "analyseIfAddressTaken")
+      internalError(c.config, n.info, "analyseIfAddressTaken")
       return
     if skipTypes(n.sons[1].sym.typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}:
       incl(n.sons[1].sym.flags, sfAddrTaken)
       result = newHiddenAddrTaken(c, n)
   of nkBracketExpr:
-    checkMinSonsLen(n, 1)
+    checkMinSonsLen(n, 1, c.config)
     if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}:
       if n.sons[0].kind == nkSym: incl(n.sons[0].sym.flags, sfAddrTaken)
       result = newHiddenAddrTaken(c, n)
@@ -505,7 +517,7 @@ proc analyseIfAddressTaken(c: PContext, n: PNode): PNode =
     result = newHiddenAddrTaken(c, n)
 
 proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
-  checkMinSonsLen(n, 1)
+  checkMinSonsLen(n, 1, c.config)
   const
     FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl,
       mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap,
@@ -524,14 +536,14 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
         let it = n[i]
         if isAssignable(c, it) notin {arLValue, arLocalLValue}:
           if it.kind != nkHiddenAddr:
-            localError(it.info, errVarForOutParamNeededX, $it)
+            localError(c.config, it.info, errVarForOutParamNeededX % $it)
     # bug #5113: disallow newSeq(result) where result is a 'var T':
     if n[0].sym.magic in {mNew, mNewFinalize, mNewSeq}:
       var arg = n[1] #.skipAddr
       if arg.kind == nkHiddenDeref: arg = arg[0]
       if arg.kind == nkSym and arg.sym.kind == skResult and
           arg.typ.skipTypes(abstractInst).kind in {tyVar, tyLent}:
-        localError(n.info, errXStackEscape, renderTree(n[1], {renderNoComments}))
+        localError(c.config, n.info, errXStackEscape % renderTree(n[1], {renderNoComments}))
 
     return
   for i in countup(1, sonsLen(n) - 1):
@@ -560,14 +572,14 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
     call.add(n.sons[0])
     var allConst = true
     for i in 1 ..< n.len:
-      var a = getConstExpr(c.module, n.sons[i])
+      var a = getConstExpr(c.module, n.sons[i], c.graph)
       if a == nil:
         allConst = false
         a = n.sons[i]
         if a.kind == nkHiddenStdConv: a = a.sons[1]
       call.add(a)
     if allConst:
-      result = semfold.getConstExpr(c.module, call)
+      result = semfold.getConstExpr(c.module, call, c.graph)
       if result.isNil: result = n
       else: return result
 
@@ -589,7 +601,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
   if {sfNoSideEffect, sfCompileTime} * callee.flags != {} and
      {sfForward, sfImportc} * callee.flags == {} and n.typ != nil:
     if sfCompileTime notin callee.flags and
-        optImplicitStatic notin gOptions: return
+        optImplicitStatic notin c.config.options: return
 
     if callee.magic notin ctfeWhitelist: return
     if callee.kind notin {skProc, skFunc, skConverter} or callee.isGenericRoutine:
@@ -600,17 +612,17 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
     var call = newNodeIT(nkCall, n.info, n.typ)
     call.add(n.sons[0])
     for i in 1 ..< n.len:
-      let a = getConstExpr(c.module, n.sons[i])
+      let a = getConstExpr(c.module, n.sons[i], c.graph)
       if a == nil: return n
       call.add(a)
     #echo "NOW evaluating at compile time: ", call.renderTree
     if sfCompileTime in callee.flags:
-      result = evalStaticExpr(c.module, c.cache, c.graph.config, call, c.p.owner)
+      result = evalStaticExpr(c.module, c.cache, c.graph, call, c.p.owner)
       if result.isNil:
-        localError(n.info, errCannotInterpretNodeX, renderTree(call))
+        localError(c.config, n.info, errCannotInterpretNodeX % renderTree(call))
       else: result = fixupTypeAfterEval(c, result, n)
     else:
-      result = evalConstExpr(c.module, c.cache, c.graph.config, call)
+      result = evalConstExpr(c.module, c.cache, c.graph, call)
       if result.isNil: result = n
       else: result = fixupTypeAfterEval(c, result, n)
     #if result != n:
@@ -619,9 +631,9 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
 proc semStaticExpr(c: PContext, n: PNode): PNode =
   let a = semExpr(c, n.sons[0])
   if a.findUnresolvedStatic != nil: return a
-  result = evalStaticExpr(c.module, c.cache, c.graph.config, a, c.p.owner)
+  result = evalStaticExpr(c.module, c.cache, c.graph, a, c.p.owner)
   if result.isNil:
-    localError(n.info, errCannotInterpretNodeX, renderTree(n))
+    localError(c.config, n.info, errCannotInterpretNodeX % renderTree(n))
     result = emptyNode
   else:
     result = fixupTypeAfterEval(c, result, a)
@@ -641,14 +653,14 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
 
   if result != nil:
     if result.sons[0].kind != nkSym:
-      internalError("semOverloadedCallAnalyseEffects")
+      internalError(c.config, "semOverloadedCallAnalyseEffects")
       return
     let callee = result.sons[0].sym
     case callee.kind
     of skMacro, skTemplate: discard
     else:
       if callee.kind == skIterator and callee.id == c.p.owner.id:
-        localError(n.info, errRecursiveDependencyX, callee.name.s)
+        localError(c.config, n.info, errRecursiveDependencyX % callee.name.s)
         # error correction, prevents endless for loop elimination in transf.
         # See bug #2051:
         result.sons[0] = newSymNode(errorSym(c, n))
@@ -696,10 +708,10 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
 
 proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
   result = nil
-  checkMinSonsLen(n, 1)
+  checkMinSonsLen(n, 1, c.config)
   var prc = n.sons[0]
   if n.sons[0].kind == nkDotExpr:
-    checkSonsLen(n.sons[0], 2)
+    checkSonsLen(n.sons[0], 2, c.config)
     let n0 = semFieldAccess(c, n.sons[0])
     if n0.kind == nkDotCall:
       # it is a static call!
@@ -732,11 +744,11 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
     if m.state != csMatch:
       if errorOutputs == {}:
         # speed up error generation:
-        globalError(n.info, errTypeMismatch, "")
+        globalError(c.config, n.info, "type mismatch")
         return emptyNode
       else:
         var hasErrorType = false
-        var msg = msgKindToString(errTypeMismatch)
+        var msg = "type mismatch: got <"
         for i in countup(1, sonsLen(n) - 1):
           if i > 1: add(msg, ", ")
           let nt = n.sons[i].typ
@@ -745,9 +757,9 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
             hasErrorType = true
             break
         if not hasErrorType:
-          add(msg, ">\n" & msgKindToString(errButExpected) & "\n" &
+          add(msg, ">\nbut expected one of: \n" &
               typeToString(n.sons[0].typ))
-          localError(n.info, errGenerated, msg)
+          localError(c.config, n.info, msg)
         return errorNode(c, n)
       result = nil
     else:
@@ -790,11 +802,11 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
 proc buildEchoStmt(c: PContext, n: PNode): PNode =
   # we MUST not check 'n' for semantics again here! But for now we give up:
   result = newNodeI(nkCall, n.info)
-  var e = strTableGet(magicsys.systemModule.tab, getIdent"echo")
+  var e = strTableGet(c.graph.systemModule.tab, getIdent"echo")
   if e != nil:
     add(result, newSymNode(e))
   else:
-    localError(n.info, errSystemNeeds, "echo")
+    localError(c.config, n.info, "system needs: echo")
     add(result, errorNode(c, n))
   add(result, n)
   result = semExpr(c, result)
@@ -838,8 +850,8 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
       result = lookupInRecordAndBuildCheck(c, n, r.sons[i], field, check)
       if result != nil: return
   of nkRecCase:
-    checkMinSonsLen(r, 2)
-    if (r.sons[0].kind != nkSym): illFormedAst(r)
+    checkMinSonsLen(r, 2, c.config)
+    if (r.sons[0].kind != nkSym): illFormedAst(r, c.config)
     result = lookupInRecordAndBuildCheck(c, n, r.sons[0], field, check)
     if result != nil: return
     let setType = createSetType(c, r.sons[0].typ)
@@ -857,8 +869,8 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
             addSon(check, ast.emptyNode) # make space for access node
           s = newNodeIT(nkCurly, n.info, setType)
           for j in countup(0, sonsLen(it) - 2): addSon(s, copyTree(it.sons[j]))
-          var inExpr = newNodeIT(nkCall, n.info, getSysType(tyBool))
-          addSon(inExpr, newSymNode(opContains, n.info))
+          var inExpr = newNodeIT(nkCall, n.info, getSysType(c.graph, n.info, tyBool))
+          addSon(inExpr, newSymNode(c.graph.opContains, n.info))
           addSon(inExpr, s)
           addSon(inExpr, copyTree(r.sons[0]))
           addSon(check, inExpr)
@@ -870,19 +882,19 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
           if check == nil:
             check = newNodeI(nkCheckedFieldExpr, n.info)
             addSon(check, ast.emptyNode) # make space for access node
-          var inExpr = newNodeIT(nkCall, n.info, getSysType(tyBool))
-          addSon(inExpr, newSymNode(opContains, n.info))
+          var inExpr = newNodeIT(nkCall, n.info, getSysType(c.graph, n.info, tyBool))
+          addSon(inExpr, newSymNode(c.graph.opContains, n.info))
           addSon(inExpr, s)
           addSon(inExpr, copyTree(r.sons[0]))
-          var notExpr = newNodeIT(nkCall, n.info, getSysType(tyBool))
-          addSon(notExpr, newSymNode(opNot, n.info))
+          var notExpr = newNodeIT(nkCall, n.info, getSysType(c.graph, n.info, tyBool))
+          addSon(notExpr, newSymNode(c.graph.opNot, n.info))
           addSon(notExpr, inExpr)
           addSon(check, notExpr)
           return
-      else: illFormedAst(it)
+      else: illFormedAst(it, c.config)
   of nkSym:
     if r.sym.name.id == field.id: result = r.sym
-  else: illFormedAst(n)
+  else: illFormedAst(n, c.config)
 
 const
   tyTypeParamsHolders = {tyGenericInst, tyCompositeTypeClass}
@@ -937,12 +949,12 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
   let s = getGenSym(c, sym)
   case s.kind
   of skConst:
-    markUsed(n.info, s, c.graph.usageSym)
+    markUsed(c.config, n.info, s, c.graph.usageSym)
     styleCheckUse(n.info, s)
     case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
     of  tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
         tyTuple, tySet, tyUInt..tyUInt64:
-      if s.magic == mNone: result = inlineConst(n, s)
+      if s.magic == mNone: result = inlineConst(c, n, s)
       else: result = newSymNode(s, n.info)
     of tyArray, tySequence:
       # Consider::
@@ -955,14 +967,14 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
       # It is clear that ``[]`` means two totally different things. Thus, we
       # copy `x`'s AST into each context, so that the type fixup phase can
       # deal with two different ``[]``.
-      if s.ast.len == 0: result = inlineConst(n, s)
+      if s.ast.len == 0: result = inlineConst(c, n, s)
       else: result = newSymNode(s, n.info)
     else:
       result = newSymNode(s, n.info)
   of skMacro:
     if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or
        (n.kind notin nkCallKinds and s.requiredParams > 0):
-      markUsed(n.info, s, c.graph.usageSym)
+      markUsed(c.config, n.info, s, c.graph.usageSym)
       styleCheckUse(n.info, s)
       result = symChoice(c, n, s, scClosed)
     else:
@@ -971,13 +983,13 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
     if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or
        (n.kind notin nkCallKinds and s.requiredParams > 0) or
        sfCustomPragma in sym.flags:
-      markUsed(n.info, s, c.graph.usageSym)
+      markUsed(c.config, n.info, s, c.graph.usageSym)
       styleCheckUse(n.info, s)
       result = symChoice(c, n, s, scClosed)
     else:
       result = semTemplateExpr(c, n, s, flags)
   of skParam:
-    markUsed(n.info, s, c.graph.usageSym)
+    markUsed(c.config, n.info, s, c.graph.usageSym)
     styleCheckUse(n.info, s)
     if s.typ != nil and s.typ.kind == tyStatic and s.typ.n != nil:
       # XXX see the hack in sigmatch.nim ...
@@ -987,19 +999,19 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
         # gensym'ed parameters that nevertheless have been forward declared
         # need a special fixup:
         let realParam = c.p.owner.typ.n[s.position+1]
-        internalAssert realParam.kind == nkSym and realParam.sym.kind == skParam
+        internalAssert c.config, realParam.kind == nkSym and realParam.sym.kind == skParam
         return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info)
       elif c.p.owner.kind == skMacro:
         # gensym'ed macro parameters need a similar hack (see bug #1944):
         var u = searchInScopes(c, s.name)
-        internalAssert u != nil and u.kind == skParam and u.owner == s.owner
+        internalAssert c.config, u != nil and u.kind == skParam and u.owner == s.owner
         return newSymNode(u, n.info)
     result = newSymNode(s, n.info)
   of skVar, skLet, skResult, skForVar:
     if s.magic == mNimvm:
-      localError(n.info, "illegal context for 'nimvm' magic")
+      localError(c.config, n.info, "illegal context for 'nimvm' magic")
 
-    markUsed(n.info, s, c.graph.usageSym)
+    markUsed(c.config, n.info, s, c.graph.usageSym)
     styleCheckUse(n.info, s)
     result = newSymNode(s, n.info)
     # We cannot check for access to outer vars for example because it's still
@@ -1017,7 +1029,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
       n.typ = s.typ
       return n
   of skType:
-    markUsed(n.info, s, c.graph.usageSym)
+    markUsed(c.config, n.info, s, c.graph.usageSym)
     styleCheckUse(n.info, s)
     if s.typ.kind == tyStatic and s.typ.n != nil:
       return s.typ.n
@@ -1039,7 +1051,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
           if f != nil and fieldVisible(c, f):
             # is the access to a public field or in the same module or in a friend?
             doAssert f == s
-            markUsed(n.info, f, c.graph.usageSym)
+            markUsed(c.config, n.info, f, c.graph.usageSym)
             styleCheckUse(n.info, f)
             result = newNodeIT(nkDotExpr, n.info, f.typ)
             result.add makeDeref(newSymNode(p.selfSym))
@@ -1052,23 +1064,23 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
           if ty.sons[0] == nil: break
           ty = skipTypes(ty.sons[0], skipPtrs)
     # old code, not sure if it's live code:
-    markUsed(n.info, s, c.graph.usageSym)
+    markUsed(c.config, n.info, s, c.graph.usageSym)
     styleCheckUse(n.info, s)
     result = newSymNode(s, n.info)
   else:
-    markUsed(n.info, s, c.graph.usageSym)
+    markUsed(c.config, n.info, s, c.graph.usageSym)
     styleCheckUse(n.info, s)
     result = newSymNode(s, n.info)
 
 proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
   ## returns nil if it's not a built-in field access
-  checkSonsLen(n, 2)
+  checkSonsLen(n, 2, c.config)
   # tests/bind/tbindoverload.nim wants an early exit here, but seems to
   # work without now. template/tsymchoicefield doesn't like an early exit
   # here at all!
   #if isSymChoice(n.sons[1]): return
   when defined(nimsuggest):
-    if gCmd == cmdIdeTools:
+    if c.config.cmd == cmdIdeTools:
       suggestExpr(c, n)
       if exactEquals(gTrackPos, n[1].info): suggestExprNoCheck(c, n)
 
@@ -1078,14 +1090,14 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
       result = symChoice(c, n, s, scClosed)
       if result.kind == nkSym: result = semSym(c, n, s, flags)
     else:
-      markUsed(n.sons[1].info, s, c.graph.usageSym)
+      markUsed(c.config, n.sons[1].info, s, c.graph.usageSym)
       result = semSym(c, n, s, flags)
     styleCheckUse(n.sons[1].info, s)
     return
 
   n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType})
   #restoreOldStyleType(n.sons[0])
-  var i = considerQuotedIdent(n.sons[1], n)
+  var i = considerQuotedIdent(c.config, n.sons[1], n)
   var ty = n.sons[0].typ
   var f: PSym = nil
   result = nil
@@ -1142,7 +1154,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
         result = newSymNode(f)
         result.info = n.info
         result.typ = ty
-        markUsed(n.info, f, c.graph.usageSym)
+        markUsed(c.config, n.info, f, c.graph.usageSym)
         styleCheckUse(n.info, f)
         return
     of tyObject, tyTuple:
@@ -1173,7 +1185,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
     if f != nil:
       if fieldVisible(c, f):
         # is the access to a public field or in the same module or in a friend?
-        markUsed(n.sons[1].info, f, c.graph.usageSym)
+        markUsed(c.config, n.sons[1].info, f, c.graph.usageSym)
         styleCheckUse(n.sons[1].info, f)
         n.sons[0] = makeDeref(n.sons[0])
         n.sons[1] = newSymNode(f) # we now have the correct field
@@ -1187,7 +1199,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
   elif ty.kind == tyTuple and ty.n != nil:
     f = getSymFromList(ty.n, i)
     if f != nil:
-      markUsed(n.sons[1].info, f, c.graph.usageSym)
+      markUsed(c.config, n.sons[1].info, f, c.graph.usageSym)
       styleCheckUse(n.sons[1].info, f)
       n.sons[0] = makeDeref(n.sons[0])
       n.sons[1] = newSymNode(f)
@@ -1205,7 +1217,7 @@ proc dotTransformation(c: PContext, n: PNode): PNode =
     addSon(result, n.sons[1])
     addSon(result, copyTree(n[0]))
   else:
-    var i = considerQuotedIdent(n.sons[1], n)
+    var i = considerQuotedIdent(c.config, n.sons[1], n)
     result = newNodeI(nkDotCall, n.info)
     result.flags.incl nfDotField
     addSon(result, newIdentNode(i, n[1].info))
@@ -1224,7 +1236,7 @@ proc buildOverloadedSubscripts(n: PNode, ident: PIdent): PNode =
   for i in 0 .. n.len-1: result.add(n[i])
 
 proc semDeref(c: PContext, n: PNode): PNode =
-  checkSonsLen(n, 1)
+  checkSonsLen(n, 1, c.config)
   n.sons[0] = semExprWithType(c, n.sons[0])
   result = n
   var t = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyLent, tyAlias, tySink})
@@ -1242,7 +1254,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
     result = newNodeIT(nkDerefExpr, x.info, x.typ)
     result.add(x[0])
     return
-  checkMinSonsLen(n, 2)
+  checkMinSonsLen(n, 2, c.config)
   # make sure we don't evaluate generic macros/templates
   n.sons[0] = semExprWithType(c, n.sons[0],
                               {efNoEvaluateGeneric})
@@ -1256,7 +1268,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
     for i in countup(1, sonsLen(n) - 1):
       n.sons[i] = semExprWithType(c, n.sons[i],
                                   flags*{efInTypeof, efDetermineType})
-    var indexType = if arr.kind == tyArray: arr.sons[0] else: getSysType(tyInt)
+    var indexType = if arr.kind == tyArray: arr.sons[0] else: getSysType(c.graph, n.info, tyInt)
     var arg = indexTypesMatch(c, indexType, n.sons[1].typ, n.sons[1])
     if arg != nil:
       n.sons[1] = arg
@@ -1279,7 +1291,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
         {tyInt..tyInt64}:
       var idx = getOrdValue(n.sons[1])
       if idx >= 0 and idx < sonsLen(arr): n.typ = arr.sons[int(idx)]
-      else: localError(n.info, errInvalidIndexValueForTuple)
+      else: localError(c.config, n.info, "invalid index value for tuple subscript")
       result = n
     else:
       result = nil
@@ -1319,7 +1331,7 @@ proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
     result = semExpr(c, buildOverloadedSubscripts(n, getIdent"[]"))
 
 proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
-  var id = considerQuotedIdent(a[1], a)
+  var id = considerQuotedIdent(c.config, a[1], a)
   var setterId = newIdentNode(getIdent(id.s & '='), n.info)
   # a[0] is already checked for semantics, that does ``builtinFieldAccess``
   # this is ugly. XXX Semantic checking should use the ``nfSem`` flag for
@@ -1342,10 +1354,10 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode =
   let root = exprRoot(n)
   if root != nil and root.owner == c.p.owner:
     if root.kind in {skLet, skVar, skTemp} and sfGlobal notin root.flags:
-      localError(n.info, "'$1' escapes its stack frame; context: '$2'; see $3/var_t_return.html" % [
+      localError(c.config, n.info, "'$1' escapes its stack frame; context: '$2'; see $3/var_t_return.html" % [
         root.name.s, renderTree(n, {renderNoComments}), explanationsBaseUrl])
     elif root.kind == skParam and root.position != 0:
-      localError(n.info, "'$1' is not the first parameter; context: '$2'; see $3/var_t_return.html" % [
+      localError(c.config, n.info, "'$1' is not the first parameter; context: '$2'; see $3/var_t_return.html" % [
         root.name.s, renderTree(n, {renderNoComments}), explanationsBaseUrl])
   case n.kind
   of nkHiddenAddr, nkAddr: return n
@@ -1356,9 +1368,9 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode =
   let valid = isAssignable(c, n)
   if valid != arLValue:
     if valid == arLocalLValue:
-      localError(n.info, errXStackEscape, renderTree(n, {renderNoComments}))
+      localError(c.config, n.info, errXStackEscape % renderTree(n, {renderNoComments}))
     elif not isLent:
-      localError(n.info, errExprHasNoAddress)
+      localError(c.config, n.info, errExprHasNoAddress)
   result = newNodeIT(nkHiddenAddr, n.info, makePtrType(c, n.typ))
   result.add(n)
 
@@ -1375,7 +1387,7 @@ template resultTypeIsInferrable(typ: PType): untyped =
   typ.isMetaType and typ.kind != tyTypeDesc
 
 proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
-  checkSonsLen(n, 2)
+  checkSonsLen(n, 2, c.config)
   var a = n.sons[0]
   case a.kind
   of nkDotExpr:
@@ -1428,7 +1440,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
         isAssignable(c, a) == arNone) or
       skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs}:
     # Direct assignment to a discriminant is allowed!
-    localError(a.info, errXCannotBeAssignedTo,
+    localError(c.config, a.info, errXCannotBeAssignedTo %
                renderTree(a, {renderNoComments}))
   else:
     let
@@ -1444,12 +1456,12 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
         if rhsTyp.kind in tyUserTypeClasses and rhsTyp.isResolvedUserTypeClass:
           rhsTyp = rhsTyp.lastSon
         if cmpTypes(c, lhs.typ, rhsTyp) in {isGeneric, isEqual}:
-          internalAssert c.p.resultSym != nil
+          internalAssert c.config, c.p.resultSym != nil
           lhs.typ = rhsTyp
           c.p.resultSym.typ = rhsTyp
           c.p.owner.typ.sons[0] = rhsTyp
         else:
-          typeMismatch(n.info, lhs.typ, rhsTyp)
+          typeMismatch(c.config, n.info, lhs.typ, rhsTyp)
 
     n.sons[1] = fitNode(c, le, rhs, n.info)
     if destructor notin c.features:
@@ -1465,7 +1477,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
 
 proc semReturn(c: PContext, n: PNode): PNode =
   result = n
-  checkSonsLen(n, 1)
+  checkSonsLen(n, 1, c.config)
   if c.p.owner.kind in {skConverter, skMethod, skProc, skFunc, skMacro} or (
      c.p.owner.kind == skIterator and c.p.owner.typ.callConv == ccClosure):
     if n.sons[0].kind != nkEmpty:
@@ -1479,9 +1491,9 @@ proc semReturn(c: PContext, n: PNode): PNode =
         if n[0][1].kind == nkSym and n[0][1].sym == c.p.resultSym:
           n.sons[0] = ast.emptyNode
       else:
-        localError(n.info, errNoReturnTypeDeclared)
+        localError(c.config, n.info, errNoReturnTypeDeclared)
   else:
-    localError(n.info, errXNotAllowedHere, "\'return\'")
+    localError(c.config, n.info, "'return' not allowed here")
 
 proc semProcBody(c: PContext, n: PNode): PNode =
   openScope(c)
@@ -1496,7 +1508,7 @@ proc semProcBody(c: PContext, n: PNode): PNode =
       #   nil
       #   # comment
       # are not expressions:
-      fixNilType(result)
+      fixNilType(c, result)
     else:
       var a = newNodeI(nkAsgn, n.info, 2)
       a.sons[0] = newSymNode(c.p.resultSym)
@@ -1512,7 +1524,7 @@ proc semProcBody(c: PContext, n: PNode): PNode =
       c.p.resultSym.typ = errorType(c)
       c.p.owner.typ.sons[0] = nil
     else:
-      localError(c.p.resultSym.info, errCannotInferReturnType)
+      localError(c.config, c.p.resultSym.info, errCannotInferReturnType)
 
   closeScope(c)
 
@@ -1536,16 +1548,16 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) =
           var a = n.sons[0].sons[1]
           a.sons[i] = takeImplicitAddr(c, a.sons[i], false)
         else:
-          localError(n.sons[0].info, errXExpected, "tuple constructor")
+          localError(c.config, n.sons[0].info, errXExpected, "tuple constructor")
   else: discard
 
 proc semYield(c: PContext, n: PNode): PNode =
   result = n
-  checkSonsLen(n, 1)
+  checkSonsLen(n, 1, c.config)
   if c.p.owner == nil or c.p.owner.kind != skIterator:
-    localError(n.info, errYieldNotAllowedHere)
+    localError(c.config, n.info, errYieldNotAllowedHere)
   elif oldIterTransf in c.features and c.p.inTryStmt > 0 and c.p.owner.typ.callConv != ccInline:
-    localError(n.info, errYieldNotAllowedInTryStmt)
+    localError(c.config, n.info, errYieldNotAllowedInTryStmt)
   elif n.sons[0].kind != nkEmpty:
     n.sons[0] = semExprWithType(c, n.sons[0]) # check for type compatibility:
     var iterType = c.p.owner.typ
@@ -1553,7 +1565,7 @@ proc semYield(c: PContext, n: PNode): PNode =
     if restype != nil:
       if restype.kind != tyExpr:
         n.sons[0] = fitNode(c, restype, n.sons[0], n.info)
-      if n.sons[0].typ == nil: internalError(n.info, "semYield")
+      if n.sons[0].typ == nil: internalError(c.config, n.info, "semYield")
 
       if resultTypeIsInferrable(restype):
         let inferred = n.sons[0].typ
@@ -1561,9 +1573,9 @@ proc semYield(c: PContext, n: PNode): PNode =
 
       semYieldVarResult(c, n, restype)
     else:
-      localError(n.info, errCannotReturnExpr)
+      localError(c.config, n.info, errCannotReturnExpr)
   elif c.p.owner.typ.sons[0] != nil:
-    localError(n.info, errGenerated, "yield statement must yield a value")
+    localError(c.config, n.info, errGenerated, "yield statement must yield a value")
 
 proc lookUpForDefined(c: PContext, i: PIdent, onlyCurrentScope: bool): PSym =
   if onlyCurrentScope:
@@ -1578,37 +1590,37 @@ proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
   of nkDotExpr:
     result = nil
     if onlyCurrentScope: return
-    checkSonsLen(n, 2)
+    checkSonsLen(n, 2, c.config)
     var m = lookUpForDefined(c, n.sons[0], onlyCurrentScope)
     if m != nil and m.kind == skModule:
-      let ident = considerQuotedIdent(n[1], n)
+      let ident = considerQuotedIdent(c.config, n[1], n)
       if m == c.module:
         result = strTableGet(c.topLevelScope.symbols, ident)
       else:
         result = strTableGet(m.tab, ident)
   of nkAccQuoted:
-    result = lookUpForDefined(c, considerQuotedIdent(n), onlyCurrentScope)
+    result = lookUpForDefined(c, considerQuotedIdent(c.config, n), onlyCurrentScope)
   of nkSym:
     result = n.sym
   of nkOpenSymChoice, nkClosedSymChoice:
     result = n.sons[0].sym
   else:
-    localError(n.info, errIdentifierExpected, renderTree(n))
+    localError(c.config, n.info, "identifier expected, but got: " & renderTree(n))
     result = nil
 
 proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode =
-  checkSonsLen(n, 2)
+  checkSonsLen(n, 2, c.config)
   # we replace this node by a 'true' or 'false' node:
   result = newIntNode(nkIntLit, 0)
-  if not onlyCurrentScope and considerQuotedIdent(n[0], n).s == "defined":
+  if not onlyCurrentScope and considerQuotedIdent(c.config, n[0], n).s == "defined":
     if n.sons[1].kind != nkIdent:
-      localError(n.info, "obsolete usage of 'defined', use 'declared' instead")
-    elif condsyms.isDefined(n.sons[1].ident):
+      localError(c.config, n.info, "obsolete usage of 'defined', use 'declared' instead")
+    elif isDefined(c.config, n.sons[1].ident.s):
       result.intVal = 1
   elif lookUpForDefined(c, n.sons[1], onlyCurrentScope) != nil:
     result.intVal = 1
   result.info = n.info
-  result.typ = getSysType(tyBool)
+  result.typ = getSysType(c.graph, n.info, tyBool)
 
 proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym =
   ## The argument to the proc should be nkCall(...) or similar
@@ -1620,12 +1632,12 @@ proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym =
       return errorSym(c, n[0])
 
     if expandedSym.kind notin {skMacro, skTemplate}:
-      localError(n.info, errXisNoMacroOrTemplate, expandedSym.name.s)
+      localError(c.config, n.info, "'$1' is not a macro or template" % expandedSym.name.s)
       return errorSym(c, n[0])
 
     result = expandedSym
   else:
-    localError(n.info, errXisNoMacroOrTemplate, n.renderTree)
+    localError(c.config, n.info, "'$1' is not a macro or template" % n.renderTree)
     result = errorSym(c, n)
 
 proc expectString(c: PContext, n: PNode): string =
@@ -1633,11 +1645,7 @@ proc expectString(c: PContext, n: PNode): string =
   if n.kind in nkStrKinds:
     return n.strVal
   else:
-    localError(n.info, errStringLiteralExpected)
-
-proc getMagicSym(magic: TMagic): PSym =
-  result = newSym(skProc, getIdent($magic), systemModule, gCodegenLineInfo)
-  result.magic = magic
+    localError(c.config, n.info, errStringLiteralExpected)
 
 proc newAnonSym(c: PContext; kind: TSymKind, info: TLineInfo): PSym =
   result = newSym(kind, c.cache.idAnon, getCurrOwner(c), info)
@@ -1651,7 +1659,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
     if expandedSym.kind == skError: return n
 
     macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
-    markUsed(n.info, expandedSym, c.graph.usageSym)
+    markUsed(c.config, n.info, expandedSym, c.graph.usageSym)
     styleCheckUse(n.info, expandedSym)
 
   if isCallExpr(macroCall):
@@ -1670,26 +1678,25 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
         inc cands
       symx = nextOverloadIter(o, c, headSymbol)
     if cands == 0:
-      localError(n.info, "expected a template that takes " & $(macroCall.len-1) & " arguments")
+      localError(c.config, n.info, "expected a template that takes " & $(macroCall.len-1) & " arguments")
     elif cands >= 2:
-      localError(n.info, "ambiguous symbol in 'getAst' context: " & $macroCall)
+      localError(c.config, n.info, "ambiguous symbol in 'getAst' context: " & $macroCall)
     else:
       let info = macroCall.sons[0].info
       macroCall.sons[0] = newSymNode(cand, info)
-      markUsed(info, cand, c.graph.usageSym)
+      markUsed(c.config, info, cand, c.graph.usageSym)
       styleCheckUse(info, cand)
 
     # we just perform overloading resolution here:
     #n.sons[1] = semOverloadedCall(c, macroCall, macroCall, {skTemplate, skMacro})
   else:
-    localError(n.info, "getAst takes a call, but got " & n.renderTree)
+    localError(c.config, n.info, "getAst takes a call, but got " & n.renderTree)
   # Preserve the magic symbol in order to be handled in evals.nim
-  internalAssert n.sons[0].sym.magic == mExpandToAst
+  internalAssert c.config, n.sons[0].sym.magic == mExpandToAst
   #n.typ = getSysSym("NimNode").typ # expandedSym.getReturnType
   if n.kind == nkStmtList and n.len == 1: result = n[0]
   else: result = n
-  result.typ = if getCompilerProc("NimNode") != nil: sysTypeFromName"NimNode"
-               else: sysTypeFromName"PNimrodNode"
+  result.typ = sysTypeFromName(c.graph, n.info, "NimNode")
 
 proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
                     flags: TExprFlags = {}): PNode =
@@ -1699,7 +1706,7 @@ proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
   else:
     result = semDirectOp(c, n, flags)
 
-proc processQuotations(n: var PNode, op: string,
+proc processQuotations(c: PContext; n: var PNode, op: string,
                        quotes: var seq[PNode],
                        ids: var seq[PNode]) =
   template returnQuote(q) =
@@ -1709,7 +1716,7 @@ proc processQuotations(n: var PNode, op: string,
     return
 
   if n.kind == nkPrefix:
-    checkSonsLen(n, 2)
+    checkSonsLen(n, 2, c.config)
     if n[0].kind == nkIdent:
       var examinedOp = n[0].ident.s
       if examinedOp == op:
@@ -1720,10 +1727,10 @@ proc processQuotations(n: var PNode, op: string,
     returnQuote n[0]
 
   for i in 0 ..< n.safeLen:
-    processQuotations(n.sons[i], op, quotes, ids)
+    processQuotations(c, n.sons[i], op, quotes, ids)
 
 proc semQuoteAst(c: PContext, n: PNode): PNode =
-  internalAssert n.len == 2 or n.len == 3
+  internalAssert c.config, n.len == 2 or n.len == 3
   # We transform the do block into a template with a param for
   # each interpolation. We'll pass this template to getAst.
   var
@@ -1736,9 +1743,9 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
       # this will store the generated param names
 
   if quotedBlock.kind != nkStmtList:
-    localError(n.info, errXExpected, "block")
+    localError(c.config, n.info, errXExpected, "block")
 
-  processQuotations(quotedBlock, op, quotes, ids)
+  processQuotations(c, quotedBlock, op, quotes, ids)
 
   var dummyTemplate = newProcNode(
     nkTemplateDef, quotedBlock.info, quotedBlock,
@@ -1746,27 +1753,27 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
 
   if ids.len > 0:
     dummyTemplate.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
-    dummyTemplate[paramsPos].add getSysSym("typed").newSymNode # return type
-    ids.add getSysSym("untyped").newSymNode # params type
+    dummyTemplate[paramsPos].add getSysSym(c.graph, n.info, "typed").newSymNode # return type
+    ids.add getSysSym(c.graph, n.info, "untyped").newSymNode # params type
     ids.add emptyNode # no default value
     dummyTemplate[paramsPos].add newNode(nkIdentDefs, n.info, ids)
 
   var tmpl = semTemplateDef(c, dummyTemplate)
   quotes[0] = tmpl[namePos]
   result = newNode(nkCall, n.info, @[
-    getMagicSym(mExpandToAst).newSymNode,
+     createMagic(c.graph, "getAst", mExpandToAst).newSymNode,
     newNode(nkCall, n.info, quotes)])
   result = semExpandToAst(c, result)
 
 proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   # watch out, hacks ahead:
-  let oldErrorCount = msgs.gErrorCounter
-  let oldErrorMax = msgs.gErrorMax
+  let oldErrorCount = c.config.errorCounter
+  let oldErrorMax = c.config.errorMax
   let oldCompilesId = c.compilesContextId
   inc c.compilesContextIdGenerator
   c.compilesContextId = c.compilesContextIdGenerator
   # do not halt after first error:
-  msgs.gErrorMax = high(int)
+  c.config.errorMax = high(int)
 
   # open a scope for temporary symbol inclusions:
   let oldScope = c.currentScope
@@ -1786,7 +1793,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   var err: string
   try:
     result = semExpr(c, n, flags)
-    if msgs.gErrorCounter != oldErrorCount: result = nil
+    if c.config.errorCounter != oldErrorCount: result = nil
   except ERecoverableError:
     discard
   # undo symbol table changes (as far as it's possible):
@@ -1801,8 +1808,8 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   setLen(c.graph.owners, oldOwnerLen)
   c.currentScope = oldScope
   errorOutputs = oldErrorOutputs
-  msgs.gErrorCounter = oldErrorCount
-  msgs.gErrorMax = oldErrorMax
+  c.config.errorCounter = oldErrorCount
+  c.config.errorMax = oldErrorMax
 
 proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
   # we replace this node by a 'true' or 'false' node:
@@ -1810,7 +1817,7 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
 
   result = newIntNode(nkIntLit, ord(tryExpr(c, n[1], flags) != nil))
   result.info = n.info
-  result.typ = getSysType(tyBool)
+  result.typ = getSysType(c.graph, n.info, tyBool)
 
 proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
   if sonsLen(n) == 3:
@@ -1825,15 +1832,15 @@ proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
 
 proc createFlowVar(c: PContext; t: PType; info: TLineInfo): PType =
   result = newType(tyGenericInvocation, c.module)
-  addSonSkipIntLit(result, magicsys.getCompilerProc("FlowVar").typ)
+  addSonSkipIntLit(result, magicsys.getCompilerProc(c.graph, "FlowVar").typ)
   addSonSkipIntLit(result, t)
   result = instGenericContainer(c, info, result, allowMetaTypes = false)
 
 proc instantiateCreateFlowVarCall(c: PContext; t: PType;
                                   info: TLineInfo): PSym =
-  let sym = magicsys.getCompilerProc("nimCreateFlowVar")
+  let sym = magicsys.getCompilerProc(c.graph, "nimCreateFlowVar")
   if sym == nil:
-    localError(info, errSystemNeeds, "nimCreateFlowVar")
+    localError(c.config, info, "system needs: nimCreateFlowVar")
   var bindings: TIdTable
   initIdTable(bindings)
   bindings.idTablePut(sym.ast[genericParamsPos].sons[0].typ, t)
@@ -1862,10 +1869,10 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
   result = n
   case s.magic # magics that need special treatment
   of mAddr:
-    checkSonsLen(n, 2)
+    checkSonsLen(n, 2, c.config)
     result = semAddr(c, n.sons[1], s.name.s == "unsafeAddr")
   of mTypeOf:
-    checkSonsLen(n, 2)
+    checkSonsLen(n, 2, c.config)
     result = semTypeOf(c, n.sons[1])
   #of mArrGet: result = semArrGet(c, n, flags)
   #of mArrPut: result = semArrPut(c, n, flags)
@@ -1882,12 +1889,12 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
   of mExpandToAst: result = semExpandToAst(c, n, s, flags)
   of mQuoteAst: result = semQuoteAst(c, n)
   of mAstToStr:
-    checkSonsLen(n, 2)
-    result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
-    result.typ = getSysType(tyString)
+    checkSonsLen(n, 2, c.config)
+    result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, c.graph)
+    result.typ = getSysType(c.graph, n.info, tyString)
   of mParallel:
     if parallel notin c.features:
-      localError(n.info, "use the {.experimental.} pragma to enable 'parallel'")
+      localError(c.config, n.info, "use the {.experimental.} pragma to enable 'parallel'")
     result = setMs(n, s)
     var x = n.lastSon
     if x.kind == nkDo: x = x.sons[bodyPos]
@@ -1928,7 +1935,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
       if callee.magic != mNone:
         result = magicsAfterOverloadResolution(c, result, flags)
   of mRunnableExamples:
-    if gCmd == cmdDoc and n.len >= 2 and n.lastSon.kind == nkStmtList:
+    if c.config.cmd == cmdDoc and n.len >= 2 and n.lastSon.kind == nkStmtList:
       if sfMainModule in c.module.flags:
         let inp = toFullPath(c.module.info)
         if c.runnableExamples == nil:
@@ -1973,7 +1980,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
     var it = n.sons[i]
     case it.kind
     of nkElifBranch, nkElifExpr:
-      checkSonsLen(it, 2)
+      checkSonsLen(it, 2, c.config)
       if whenNimvm:
         if semCheck:
           it.sons[1] = semExpr(c, it.sons[1])
@@ -1988,14 +1995,14 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
         elif e.intVal != 0 and result == nil:
           setResult(it.sons[1])
     of nkElse, nkElseExpr:
-      checkSonsLen(it, 1)
+      checkSonsLen(it, 1, c.config)
       if result == nil or whenNimvm:
         if semCheck:
           it.sons[0] = semExpr(c, it.sons[0])
           typ = commonType(typ, it.sons[0].typ)
         if result == nil:
           result = it.sons[0]
-    else: illFormedAst(n)
+    else: illFormedAst(n, c.config)
   if result == nil:
     result = newNodeI(nkEmpty, n.info)
   if whenNimvm: result.typ = typ
@@ -2014,7 +2021,7 @@ proc semSetConstr(c: PContext, n: PNode): PNode =
     var typ: PType = nil
     for i in countup(0, sonsLen(n) - 1):
       if isRange(n.sons[i]):
-        checkSonsLen(n.sons[i], 3)
+        checkSonsLen(n.sons[i], 3, c.config)
         n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1])
         n.sons[i].sons[2] = semExprWithType(c, n.sons[i].sons[2])
         if typ == nil:
@@ -2031,7 +2038,7 @@ proc semSetConstr(c: PContext, n: PNode): PNode =
         if typ == nil:
           typ = skipTypes(n.sons[i].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
     if not isOrdinalType(typ):
-      localError(n.info, errOrdinalTypeExpected)
+      localError(c.config, n.info, errOrdinalTypeExpected)
       typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
     elif lengthOrd(typ) > MaxSetElements:
       typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
@@ -2069,14 +2076,14 @@ proc semTableConstr(c: PContext, n: PNode): PNode =
 
       lastKey = i+1
 
-  if lastKey != n.len: illFormedAst(n)
+  if lastKey != n.len: illFormedAst(n, c.config)
   result = semExpr(c, result)
 
 type
   TParKind = enum
     paNone, paSingle, paTupleFields, paTuplePositions
 
-proc checkPar(n: PNode): TParKind =
+proc checkPar(c: PContext; n: PNode): TParKind =
   var length = sonsLen(n)
   if length == 0:
     result = paTuplePositions # ()
@@ -2091,11 +2098,11 @@ proc checkPar(n: PNode): TParKind =
       if result == paTupleFields:
         if (n.sons[i].kind != nkExprColonExpr) or
             not (n.sons[i].sons[0].kind in {nkSym, nkIdent}):
-          localError(n.sons[i].info, errNamedExprExpected)
+          localError(c.config, n.sons[i].info, errNamedExprExpected)
           return paNone
       else:
         if n.sons[i].kind == nkExprColonExpr:
-          localError(n.sons[i].info, errNamedExprNotAllowed)
+          localError(c.config, n.sons[i].info, errNamedExprNotAllowed)
           return paNone
 
 proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
@@ -2105,12 +2112,12 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
   var ids = initIntSet()
   for i in countup(0, sonsLen(n) - 1):
     if n[i].kind != nkExprColonExpr or n[i][0].kind notin {nkSym, nkIdent}:
-      illFormedAst(n.sons[i])
+      illFormedAst(n.sons[i], c.config)
     var id: PIdent
     if n.sons[i].sons[0].kind == nkIdent: id = n.sons[i].sons[0].ident
     else: id = n.sons[i].sons[0].sym.name
     if containsOrIncl(ids, id.id):
-      localError(n.sons[i].info, errFieldInitTwice, id.s)
+      localError(c.config, n.sons[i].info, errFieldInitTwice % id.s)
     n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1],
                                         flags*{efAllowDestructor})
     var f = newSymS(skField, n.sons[i].sons[0], c)
@@ -2144,14 +2151,14 @@ include semobjconstr
 proc semBlock(c: PContext, n: PNode): PNode =
   result = n
   inc(c.p.nestedBlockCounter)
-  checkSonsLen(n, 2)
+  checkSonsLen(n, 2, c.config)
   openScope(c) # BUGFIX: label is in the scope of block!
   if n.sons[0].kind != nkEmpty:
     var labl = newSymG(skLabel, n.sons[0], c)
     if sfGenSym notin labl.flags:
       addDecl(c, labl)
     n.sons[0] = newSymNode(labl, n.sons[0].info)
-    suggestSym(n.sons[0].info, labl, c.graph.usageSym)
+    suggestSym(c.config, n.sons[0].info, labl, c.graph.usageSym)
     styleCheckDef(labl)
   n.sons[1] = semExpr(c, n.sons[1])
   n.typ = n.sons[1].typ
@@ -2163,9 +2170,9 @@ proc semBlock(c: PContext, n: PNode): PNode =
 proc semExportExcept(c: PContext, n: PNode): PNode =
   let moduleName = semExpr(c, n[0])
   if moduleName.kind != nkSym or moduleName.sym.kind != skModule:
-    localError(n.info, "The export/except syntax expects a module name")
-    return
-  let exceptSet = readExceptSet(n)
+    localError(c.config, n.info, "The export/except syntax expects a module name")
+    return n
+  let exceptSet = readExceptSet(c, n)
   let exported = moduleName.sym
   strTableAdd(c.module.tab, exported)
   var i: TTabIter
@@ -2184,7 +2191,7 @@ proc semExport(c: PContext, n: PNode): PNode =
     var o: TOverloadIter
     var s = initOverloadIter(o, c, a)
     if s == nil:
-      localError(a.info, errGenerated, "cannot export: " & renderTree(a))
+      localError(c.config, a.info, errGenerated, "cannot export: " & renderTree(a))
     elif s.kind == skModule:
       # forward everything from that module:
       strTableAdd(c.module.tab, s)
@@ -2218,7 +2225,7 @@ proc shouldBeBracketExpr(n: PNode): bool =
 
 proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   result = n
-  if gCmd == cmdIdeTools: suggestExpr(c, n)
+  if c.config.cmd == cmdIdeTools: suggestExpr(c, n)
   if nfSem in n.flags: return
   case n.kind
   of nkIdent, nkAccQuoted:
@@ -2237,7 +2244,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
       if result.kind == nkSym:
         markIndirect(c, result.sym)
         # if isGenericRoutine(result.sym):
-        #   localError(n.info, errInstantiateXExplicitly, s.name.s)
+        #   localError(c.config, n.info, errInstantiateXExplicitly, s.name.s)
   of nkSym:
     # because of the changed symbol binding, this does not mean that we
     # don't have to check the symbol for semantics here again!
@@ -2245,46 +2252,46 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkEmpty, nkNone, nkCommentStmt, nkType:
     discard
   of nkNilLit:
-    if result.typ == nil: result.typ = getSysType(tyNil)
+    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyNil)
   of nkIntLit:
-    if result.typ == nil: setIntLitType(result)
+    if result.typ == nil: setIntLitType(c.graph, result)
   of nkInt8Lit:
-    if result.typ == nil: result.typ = getSysType(tyInt8)
+    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt8)
   of nkInt16Lit:
-    if result.typ == nil: result.typ = getSysType(tyInt16)
+    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt16)
   of nkInt32Lit:
-    if result.typ == nil: result.typ = getSysType(tyInt32)
+    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt32)
   of nkInt64Lit:
-    if result.typ == nil: result.typ = getSysType(tyInt64)
+    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt64)
   of nkUIntLit:
-    if result.typ == nil: result.typ = getSysType(tyUInt)
+    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt)
   of nkUInt8Lit:
-    if result.typ == nil: result.typ = getSysType(tyUInt8)
+    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt8)
   of nkUInt16Lit:
-    if result.typ == nil: result.typ = getSysType(tyUInt16)
+    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt16)
   of nkUInt32Lit:
-    if result.typ == nil: result.typ = getSysType(tyUInt32)
+    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt32)
   of nkUInt64Lit:
-    if result.typ == nil: result.typ = getSysType(tyUInt64)
+    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt64)
   #of nkFloatLit:
   #  if result.typ == nil: result.typ = getFloatLitType(result)
   of nkFloat32Lit:
-    if result.typ == nil: result.typ = getSysType(tyFloat32)
+    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyFloat32)
   of nkFloat64Lit, nkFloatLit:
-    if result.typ == nil: result.typ = getSysType(tyFloat64)
+    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyFloat64)
   of nkFloat128Lit:
-    if result.typ == nil: result.typ = getSysType(tyFloat128)
+    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyFloat128)
   of nkStrLit..nkTripleStrLit:
-    if result.typ == nil: result.typ = getSysType(tyString)
+    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyString)
   of nkCharLit:
-    if result.typ == nil: result.typ = getSysType(tyChar)
+    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyChar)
   of nkDotExpr:
     result = semFieldAccess(c, n, flags)
     if result.kind == nkDotCall:
       result.kind = nkCall
       result = semExpr(c, result, flags)
   of nkBind:
-    message(n.info, warnDeprecated, "bind")
+    message(c.config, n.info, warnDeprecated, "bind")
     result = semExpr(c, n.sons[0], flags)
   of nkTypeOfExpr, nkTupleTy, nkTupleClassTy, nkRefTy..nkEnumTy, nkStaticTy:
     if c.matchedConcept != nil and n.len == 1:
@@ -2297,13 +2304,13 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     result.typ = makeTypeDesc(c, typ)
   of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
     # check if it is an expression macro:
-    checkMinSonsLen(n, 1)
+    checkMinSonsLen(n, 1, c.config)
     #when defined(nimsuggest):
     #  if gIdeCmd == ideCon and gTrackPos == n.info: suggestExprNoCheck(c, n)
     let mode = if nfDotField in n.flags: {} else: {checkUndeclared}
     var s = qualifiedLookUp(c, n.sons[0], mode)
     if s != nil:
-      #if gCmd == cmdPretty and n.sons[0].kind == nkDotExpr:
+      #if c.config.cmd == cmdPretty and n.sons[0].kind == nkDotExpr:
       #  pretty.checkUse(n.sons[0].sons[1].info, s)
       case s.kind
       of skMacro:
@@ -2353,7 +2360,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
       else:
         result = semExpr(c, result, flags)
   of nkBracketExpr:
-    checkMinSonsLen(n, 1)
+    checkMinSonsLen(n, 1, c.config)
     result = semArrayAccess(c, n, flags)
   of nkCurlyExpr:
     result = semExpr(c, buildOverloadedSubscripts(n, getIdent"{}"), flags)
@@ -2361,7 +2368,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     var
       expr = n[0]
       pragma = n[1]
-      pragmaName = considerQuotedIdent(pragma[0])
+      pragmaName = considerQuotedIdent(c.config, pragma[0])
       flags = flags
 
     case whichKeyword(pragmaName)
@@ -2369,11 +2376,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
       flags.incl efExplain
     else:
       # what other pragmas are allowed for expressions? `likely`, `unlikely`
-      invalidPragma(n)
+      invalidPragma(c, n)
 
     result = semExpr(c, n[0], flags)
   of nkPar, nkTupleConstr:
-    case checkPar(n)
+    case checkPar(c, n)
     of paNone: result = errorNode(c, n)
     of paTuplePositions:
       var tupexp = semTuplePositionsConstr(c, n, flags)
@@ -2392,24 +2399,24 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkDerefExpr: result = semDeref(c, n)
   of nkAddr:
     result = n
-    checkSonsLen(n, 1)
+    checkSonsLen(n, 1, c.config)
     result = semAddr(c, n.sons[0])
   of nkHiddenAddr, nkHiddenDeref:
-    checkSonsLen(n, 1)
+    checkSonsLen(n, 1, c.config)
     n.sons[0] = semExpr(c, n.sons[0], flags)
   of nkCast: result = semCast(c, n)
   of nkIfExpr, nkIfStmt: result = semIf(c, n)
   of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv:
-    checkSonsLen(n, 2)
+    checkSonsLen(n, 2, c.config)
     considerGenSyms(c, n)
   of nkStringToCString, nkCStringToString, nkObjDownConv, nkObjUpConv:
-    checkSonsLen(n, 1)
+    checkSonsLen(n, 1, c.config)
     considerGenSyms(c, n)
   of nkChckRangeF, nkChckRange64, nkChckRange:
-    checkSonsLen(n, 3)
+    checkSonsLen(n, 3, c.config)
     considerGenSyms(c, n)
   of nkCheckedFieldExpr:
-    checkMinSonsLen(n, 2)
+    checkMinSonsLen(n, 2, c.config)
     considerGenSyms(c, n)
   of nkTableConstr:
     result = semTableConstr(c, n)
@@ -2453,22 +2460,22 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     #
     # works:
     if c.currentScope.depthLevel > 2 + c.compilesContextId:
-      localError(n.info, errXOnlyAtModuleScope, "import")
+      localError(c.config, n.info, errXOnlyAtModuleScope % "import")
     result = evalImport(c, n)
   of nkImportExceptStmt:
-    if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "import")
+    if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "import")
     result = evalImportExcept(c, n)
   of nkFromStmt:
-    if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "from")
+    if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "from")
     result = evalFrom(c, n)
   of nkIncludeStmt:
-    #if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "include")
+    #if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "include")
     result = evalInclude(c, n)
   of nkExportStmt:
-    if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "export")
+    if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "export")
     result = semExport(c, n)
   of nkExportExceptStmt:
-    if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "export")
+    if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "export")
     result = semExportExcept(c, n)
   of nkPragmaBlock:
     result = semPragmaBlock(c, n)
@@ -2477,14 +2484,14 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkDefer:
     n.sons[0] = semExpr(c, n.sons[0])
     if not n.sons[0].typ.isEmptyType and not implicitlyDiscardable(n.sons[0]):
-      localError(n.info, errGenerated, "'defer' takes a 'void' expression")
-    #localError(n.info, errGenerated, "'defer' not allowed in this context")
+      localError(c.config, n.info, "'defer' takes a 'void' expression")
+    #localError(c.config, n.info, errGenerated, "'defer' not allowed in this context")
   of nkGotoState, nkState:
-    if n.len != 1 and n.len != 2: illFormedAst(n)
+    if n.len != 1 and n.len != 2: illFormedAst(n, c.config)
     for i in 0 ..< n.len:
       n.sons[i] = semExpr(c, n.sons[i])
   of nkComesFrom: discard "ignore the comes from information for now"
   else:
-    localError(n.info, errInvalidExpressionX,
+    localError(c.config, n.info, "invalid expression: " &
                renderTree(n, {renderNoComments}))
   if result != nil: incl(result.flags, nfSem)
diff --git a/compiler/semfields.nim b/compiler/semfields.nim
index c5bc07d77..16d79c559 100644
--- a/compiler/semfields.nim
+++ b/compiler/semfields.nim
@@ -16,16 +16,17 @@ type
     tupleIndex: int
     field: PSym
     replaceByFieldName: bool
+    c: PContext
 
 proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
   case n.kind
   of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = n
   of nkIdent, nkSym:
     result = n
-    let ident = considerQuotedIdent(n)
+    let ident = considerQuotedIdent(c.c.config, n)
     var L = sonsLen(forLoop)
     if c.replaceByFieldName:
-      if ident.id == considerQuotedIdent(forLoop[0]).id:
+      if ident.id == considerQuotedIdent(c.c.config, forLoop[0]).id:
         let fieldName = if c.tupleType.isNil: c.field.name.s
                         elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
                         else: c.tupleType.n.sons[c.tupleIndex].sym.name.s
@@ -33,7 +34,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
         return
     # other fields:
     for i in ord(c.replaceByFieldName)..L-3:
-      if ident.id == considerQuotedIdent(forLoop[i]).id:
+      if ident.id == considerQuotedIdent(c.c.config, forLoop[i]).id:
         var call = forLoop.sons[L-2]
         var tupl = call.sons[i+1-ord(c.replaceByFieldName)]
         if c.field.isNil:
@@ -47,7 +48,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
         break
   else:
     if n.kind == nkContinueStmt:
-      localError(n.info, errGenerated,
+      localError(c.c.config, n.info,
                  "'continue' not supported in a 'fields' loop")
     result = copyNode(n)
     newSons(result, sonsLen(n))
@@ -63,6 +64,7 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
   case typ.kind
   of nkSym:
     var fc: TFieldInstCtx  # either 'tup[i]' or 'field' is valid
+    fc.c = c.c
     fc.field = typ.sym
     fc.replaceByFieldName = c.m == mFieldPairs
     openScope(c.c)
@@ -76,7 +78,7 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
     let L = forLoop.len
     let call = forLoop.sons[L-2]
     if call.len > 2:
-      localError(forLoop.info, errGenerated,
+      localError(c.c.config, forLoop.info,
                  "parallel 'fields' iterator does not work for 'case' objects")
       return
     # iterate over the selector:
@@ -99,17 +101,17 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
   of nkRecList:
     for t in items(typ): semForObjectFields(c, t, forLoop, father)
   else:
-    illFormedAstLocal(typ)
+    illFormedAstLocal(typ, c.c.config)
 
 proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
   # so that 'break' etc. work as expected, we produce
   # a 'while true: stmt; break' loop ...
   result = newNodeI(nkWhileStmt, n.info, 2)
-  var trueSymbol = strTableGet(magicsys.systemModule.tab, getIdent"true")
+  var trueSymbol = strTableGet(c.graph.systemModule.tab, getIdent"true")
   if trueSymbol == nil:
-    localError(n.info, errSystemNeeds, "true")
+    localError(c.config, n.info, "system needs: 'true'")
     trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(c), n.info)
-    trueSymbol.typ = getSysType(tyBool)
+    trueSymbol.typ = getSysType(c.graph, n.info, tyBool)
 
   result.sons[0] = newSymNode(trueSymbol, n.info)
   var stmts = newNodeI(nkStmtList, n.info)
@@ -118,18 +120,18 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
   var length = sonsLen(n)
   var call = n.sons[length-2]
   if length-2 != sonsLen(call)-1 + ord(m==mFieldPairs):
-    localError(n.info, errWrongNumberOfVariables)
+    localError(c.config, n.info, errWrongNumberOfVariables)
     return result
 
   const skippedTypesForFields = abstractVar - {tyTypeDesc} + tyUserTypeClasses
   var tupleTypeA = skipTypes(call.sons[1].typ, skippedTypesForFields)
   if tupleTypeA.kind notin {tyTuple, tyObject}:
-    localError(n.info, errGenerated, "no object or tuple type")
+    localError(c.config, n.info, errGenerated, "no object or tuple type")
     return result
   for i in 1..call.len-1:
     var tupleTypeB = skipTypes(call.sons[i].typ, skippedTypesForFields)
     if not sameType(tupleTypeA, tupleTypeB):
-      typeMismatch(call.sons[i].info, tupleTypeA, tupleTypeB)
+      typeMismatch(c.config, call.sons[i].info, tupleTypeA, tupleTypeB)
 
   inc(c.p.nestedLoopCounter)
   if tupleTypeA.kind == tyTuple:
@@ -139,6 +141,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
       var fc: TFieldInstCtx
       fc.tupleType = tupleTypeA
       fc.tupleIndex = i
+      fc.c = c
       fc.replaceByFieldName = m == mFieldPairs
       var body = instFieldLoopBody(fc, loopBody, n)
       inc c.inUnrolledContext
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index c4d79a4a3..daf9ce983 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -13,54 +13,83 @@
 import
   strutils, options, ast, astalgo, trees, treetab, nimsets, times,
   nversion, platform, math, msgs, os, condsyms, idents, renderer, types,
-  commands, magicsys
+  commands, magicsys, modulegraphs, strtabs
 
-proc getConstExpr*(m: PSym, n: PNode): PNode
+proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode =
+  case skipTypes(n.typ, abstractVarRange).kind
+  of tyInt:
+    result = newIntNode(nkIntLit, intVal)
+    # 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:
+      result.typ = getIntLitType(g, result)
+    else:
+      result.typ = n.typ
+    # hrm, this is not correct: 1 + high(int) shouldn't produce tyInt64 ...
+    #setIntLitType(result)
+  of tyChar:
+    result = newIntNode(nkCharLit, intVal)
+    result.typ = n.typ
+  else:
+    result = newIntNode(nkIntLit, intVal)
+    result.typ = n.typ
+  result.info = n.info
+
+proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode; g: ModuleGraph): PNode =
+  result = newFloatNode(nkFloatLit, floatVal)
+  if skipTypes(n.typ, abstractVarRange).kind == tyFloat:
+    result.typ = getFloatLitType(g, result)
+  else:
+    result.typ = n.typ
+  result.info = n.info
+
+proc newStrNodeT*(strVal: string, n: PNode; g: ModuleGraph): PNode =
+  result = newStrNode(nkStrLit, strVal)
+  result.typ = n.typ
+  result.info = n.info
+
+proc getConstExpr*(m: PSym, n: PNode; 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): PNode
-proc leValueConv*(a, b: PNode): bool
-proc newIntNodeT*(intVal: BiggestInt, n: PNode): PNode
-proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode
-proc newStrNodeT*(strVal: string, n: PNode): PNode
+proc evalOp*(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode
 
 proc checkInRange(n: PNode, res: BiggestInt): bool =
   if res in firstOrd(n.typ)..lastOrd(n.typ):
     result = true
 
-proc foldAdd(a, b: BiggestInt, n: PNode): PNode =
+proc foldAdd(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
   let res = a +% b
   if ((res xor a) >= 0'i64 or (res xor b) >= 0'i64) and
       checkInRange(n, res):
-    result = newIntNodeT(res, n)     
+    result = newIntNodeT(res, n, g)
 
-proc foldSub*(a, b: BiggestInt, n: PNode): PNode =
+proc foldSub*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
   let res = a -% b
   if ((res xor a) >= 0'i64 or (res xor not b) >= 0'i64) and
       checkInRange(n, res):
-    result = newIntNodeT(res, n)
+    result = newIntNodeT(res, n, g)
 
-proc foldAbs*(a: BiggestInt, n: PNode): PNode =
+proc foldAbs*(a: BiggestInt, n: PNode; g: ModuleGraph): PNode =
   if a != firstOrd(n.typ):
-    result = newIntNodeT(a, n)
-  
-proc foldMod*(a, b: BiggestInt, n: PNode): PNode =
+    result = newIntNodeT(a, n, g)
+
+proc foldMod*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
   if b != 0'i64:
-    result = newIntNodeT(a mod b, n)
+    result = newIntNodeT(a mod b, n, g)
 
-proc foldModU*(a, b: BiggestInt, n: PNode): PNode =
+proc foldModU*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
   if b != 0'i64:
-    result = newIntNodeT(a %% b, n)
+    result = newIntNodeT(a %% b, n, g)
 
-proc foldDiv*(a, b: BiggestInt, n: PNode): PNode =
+proc foldDiv*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
   if b != 0'i64 and (a != firstOrd(n.typ) or b != -1'i64):
-    result = newIntNodeT(a div b, n)
+    result = newIntNodeT(a div b, n, g)
 
-proc foldDivU*(a, b: BiggestInt, n: PNode): PNode =
+proc foldDivU*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
   if b != 0'i64:
-    result = newIntNodeT(a /% b, n)
+    result = newIntNodeT(a /% b, n, g)
 
-proc foldMul*(a, b: BiggestInt, n: PNode): PNode =
+proc foldMul*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
   let res = a *% b
   let floatProd = toBiggestFloat(a) * toBiggestFloat(b)
   let resAsFloat = toBiggestFloat(res)
@@ -68,7 +97,7 @@ proc foldMul*(a, b: BiggestInt, n: PNode): PNode =
   # Fast path for normal case: small multiplicands, and no info
   # is lost in either method.
   if resAsFloat == floatProd and checkInRange(n, res):
-    return newIntNodeT(res, n)
+    return newIntNodeT(res, n, g)
 
   # Somebody somewhere lost info. Close enough, or way off? Note
   # that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
@@ -79,44 +108,9 @@ proc foldMul*(a, b: BiggestInt, n: PNode): PNode =
   #   32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
   if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd) and
       checkInRange(n, res):
-    return newIntNodeT(res, n)
-
-# implementation
-
-proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode =
-  case skipTypes(n.typ, abstractVarRange).kind
-  of tyInt:
-    result = newIntNode(nkIntLit, intVal)
-    # 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:
-      result.typ = getIntLitType(result)
-    else:
-      result.typ = n.typ
-    # hrm, this is not correct: 1 + high(int) shouldn't produce tyInt64 ...
-    #setIntLitType(result)
-  of tyChar:
-    result = newIntNode(nkCharLit, intVal)
-    result.typ = n.typ
-  else:
-    result = newIntNode(nkIntLit, intVal)
-    result.typ = n.typ
-  result.info = n.info
-
-proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode =
-  result = newFloatNode(nkFloatLit, floatVal)
-  if skipTypes(n.typ, abstractVarRange).kind == tyFloat:
-    result.typ = getFloatLitType(result)
-  else:
-    result.typ = n.typ
-  result.info = n.info
-
-proc newStrNodeT(strVal: string, n: PNode): PNode =
-  result = newStrNode(nkStrLit, strVal)
-  result.typ = n.typ
-  result.info = n.info
+    return newIntNodeT(res, n, g)
 
-proc ordinalValToString*(a: PNode): string =
+proc ordinalValToString*(a: PNode; g: ModuleGraph): string =
   # because $ has the param ordinal[T], `a` is not necessarily an enum, but an
   # ordinal
   var x = getInt(a)
@@ -128,14 +122,14 @@ proc ordinalValToString*(a: PNode): string =
   of tyEnum:
     var n = t.n
     for i in countup(0, sonsLen(n) - 1):
-      if n.sons[i].kind != nkSym: internalError(a.info, "ordinalValToString")
+      if n.sons[i].kind != nkSym: internalError(g.config, a.info, "ordinalValToString")
       var field = n.sons[i].sym
       if field.position == x:
         if field.ast == nil:
           return field.name.s
         else:
           return field.ast.strVal
-    internalError(a.info, "no symbol for ordinal value: " & $x)
+    internalError(g.config, a.info, "no symbol for ordinal value: " & $x)
   else:
     result = $x
 
@@ -154,12 +148,12 @@ proc pickIntRange(a, b: PType): PType =
 proc isIntRangeOrLit(t: PType): bool =
   result = isIntRange(t) or isIntLit(t)
 
-proc makeRange(typ: PType, first, last: BiggestInt): PType =
+proc makeRange(typ: PType, first, last: BiggestInt; g: ModuleGraph): PType =
   let minA = min(first, last)
   let maxA = max(first, last)
   let lowerNode = newIntNode(nkIntLit, minA)
   if typ.kind == tyInt and minA == maxA:
-    result = getIntLitType(lowerNode)
+    result = getIntLitType(g, lowerNode)
   elif typ.kind in {tyUint, tyUInt64}:
     # these are not ordinal types, so you get no subrange type for these:
     result = typ
@@ -171,7 +165,7 @@ proc makeRange(typ: PType, first, last: BiggestInt): PType =
     result.n = n
     addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
 
-proc makeRangeF(typ: PType, first, last: BiggestFloat): PType =
+proc makeRangeF(typ: PType, first, last: BiggestFloat; g: ModuleGraph): PType =
   var n = newNode(nkRange)
   addSon(n, newFloatNode(nkFloatLit, min(first.float, last.float)))
   addSon(n, newFloatNode(nkFloatLit, max(first.float, last.float)))
@@ -181,9 +175,9 @@ proc makeRangeF(typ: PType, first, last: BiggestFloat): PType =
 
 proc evalIs(n, a: PNode): PNode =
   # XXX: This should use the standard isOpImpl
-  internalAssert a.kind == nkSym and a.sym.kind == skType
-  internalAssert n.sonsLen == 3 and
-    n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
+  #internalAssert a.kind == nkSym and a.sym.kind == skType
+  #internalAssert n.sonsLen == 3 and
+  #  n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
 
   let t1 = a.sym.typ
 
@@ -207,113 +201,113 @@ proc evalIs(n, a: PNode): PNode =
     result = newIntNode(nkIntLit, ord(match))
   result.typ = n.typ
 
-proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
+proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
   # b and c may be nil
   result = nil
   case m
-  of mOrd: result = newIntNodeT(getOrdValue(a), n)
-  of mChr: result = newIntNodeT(getInt(a), n)
-  of mUnaryMinusI, mUnaryMinusI64: result = newIntNodeT(- getInt(a), n)
-  of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n)
-  of mNot: result = newIntNodeT(1 - getInt(a), n)
-  of mCard: result = newIntNodeT(nimsets.cardSet(a), n)
-  of mBitnotI: result = newIntNodeT(not getInt(a), n)
-  of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n)
+  of mOrd: result = newIntNodeT(getOrdValue(a), n, g)
+  of mChr: result = newIntNodeT(getInt(a), n, g)
+  of mUnaryMinusI, mUnaryMinusI64: result = newIntNodeT(- getInt(a), n, g)
+  of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n, g)
+  of mNot: result = newIntNodeT(1 - getInt(a), n, g)
+  of mCard: result = newIntNodeT(nimsets.cardSet(a), n, g)
+  of mBitnotI: result = newIntNodeT(not getInt(a), n, g)
+  of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n, g)
   of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr:
     if a.kind == nkNilLit:
-      result = newIntNodeT(0, n)
+      result = newIntNodeT(0, n, g)
     elif a.kind in {nkStrLit..nkTripleStrLit}:
-      result = newIntNodeT(len a.strVal, n)
+      result = newIntNodeT(len a.strVal, n, g)
     else:
-      result = newIntNodeT(sonsLen(a), n) # BUGFIX
+      result = newIntNodeT(sonsLen(a), n, g)
   of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
   of mToFloat, mToBiggestFloat:
-    result = newFloatNodeT(toFloat(int(getInt(a))), n)
+    result = newFloatNodeT(toFloat(int(getInt(a))), n, g)
   # XXX: Hides overflow/underflow
-  of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n)
-  of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n)
-  of mAbsI: result = foldAbs(getInt(a), n)
+  of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n, g)
+  of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n, g)
+  of mAbsI: result = foldAbs(getInt(a), n, g)
   of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64:
     # byte(-128) = 1...1..1000_0000'64 --> 0...0..1000_0000'64
-    result = newIntNodeT(getInt(a) and (`shl`(1, getSize(a.typ) * 8) - 1), n)
-  of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n)
-  of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n)
-  of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n)
-  of mUnaryLt: result = foldSub(getOrdValue(a), 1, n)
-  of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n)
-  of mPred: result = foldSub(getOrdValue(a), getInt(b), n)
-  of mAddI: result = foldAdd(getInt(a), getInt(b), n)
-  of mSubI: result = foldSub(getInt(a), getInt(b), n)
-  of mMulI: result = foldMul(getInt(a), getInt(b), n)
+    result = newIntNodeT(getInt(a) and (`shl`(1, getSize(a.typ) * 8) - 1), n, g)
+  of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n, g)
+  of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n, g)
+  of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n, g)
+  of mUnaryLt: result = foldSub(getOrdValue(a), 1, 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 mMinI:
-    if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n)
-    else: result = newIntNodeT(getInt(a), n)
+    if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n, g)
+    else: result = newIntNodeT(getInt(a), n, g)
   of mMaxI:
-    if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n)
-    else: result = newIntNodeT(getInt(b), n)
+    if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n, g)
+    else: result = newIntNodeT(getInt(b), n, g)
   of mShlI:
     case skipTypes(n.typ, abstractRange).kind
-    of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n)
-    of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n)
-    of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n)
+    of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n, g)
+    of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n, g)
+    of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n, g)
     of tyInt64, tyInt, tyUInt..tyUInt64:
-      result = newIntNodeT(`shl`(getInt(a), getInt(b)), n)
-    else: internalError(n.info, "constant folding for shl")
+      result = newIntNodeT(`shl`(getInt(a), getInt(b)), n, g)
+    else: internalError(g.config, n.info, "constant folding for shl")
   of mShrI:
     case skipTypes(n.typ, abstractRange).kind
-    of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n)
-    of tyInt16: result = newIntNodeT(int16(getInt(a)) shr int16(getInt(b)), n)
-    of tyInt32: result = newIntNodeT(int32(getInt(a)) shr int32(getInt(b)), n)
+    of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n, g)
+    of tyInt16: result = newIntNodeT(int16(getInt(a)) shr int16(getInt(b)), n, g)
+    of tyInt32: result = newIntNodeT(int32(getInt(a)) shr int32(getInt(b)), n, g)
     of tyInt64, tyInt, tyUInt..tyUInt64:
-      result = newIntNodeT(`shr`(getInt(a), getInt(b)), n)
-    else: internalError(n.info, "constant folding for shr")
-  of mDivI: result = foldDiv(getInt(a), getInt(b), n)
-  of mModI: result = foldMod(getInt(a), getInt(b), n)
-  of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n)
-  of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n)
-  of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n)
+      result = newIntNodeT(`shr`(getInt(a), getInt(b)), n, g)
+    else: internalError(g.config, n.info, "constant folding for shr")
+  of mDivI: result = foldDiv(getInt(a), getInt(b), n, g)
+  of mModI: result = foldMod(getInt(a), getInt(b), n, 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:
     if getFloat(b) == 0.0:
-      if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n)
-      elif getFloat(b).classify == fcNegZero: result = newFloatNodeT(-Inf, n)
-      else: result = newFloatNodeT(Inf, n)
+      if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n, g)
+      elif getFloat(b).classify == fcNegZero: result = newFloatNodeT(-Inf, n, g)
+      else: result = newFloatNodeT(Inf, n, g)
     else:
-      result = newFloatNodeT(getFloat(a) / getFloat(b), n)
+      result = newFloatNodeT(getFloat(a) / getFloat(b), n, g)
   of mMaxF64:
-    if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n)
-    else: result = newFloatNodeT(getFloat(b), n)
+    if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n, g)
+    else: result = newFloatNodeT(getFloat(b), n, g)
   of mMinF64:
-    if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(b), n)
-    else: result = newFloatNodeT(getFloat(a), n)
-  of mIsNil: result = newIntNodeT(ord(a.kind == nkNilLit), n)
+    if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(b), n, g)
+    else: result = newFloatNodeT(getFloat(a), n, g)
+  of mIsNil: result = newIntNodeT(ord(a.kind == nkNilLit), n, g)
   of mLtI, mLtB, mLtEnum, mLtCh:
-    result = newIntNodeT(ord(getOrdValue(a) < getOrdValue(b)), n)
+    result = newIntNodeT(ord(getOrdValue(a) < getOrdValue(b)), n, g)
   of mLeI, mLeB, mLeEnum, mLeCh:
-    result = newIntNodeT(ord(getOrdValue(a) <= getOrdValue(b)), n)
+    result = newIntNodeT(ord(getOrdValue(a) <= getOrdValue(b)), n, g)
   of mEqI, mEqB, mEqEnum, mEqCh:
-    result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n)
-  of mLtF64: result = newIntNodeT(ord(getFloat(a) < getFloat(b)), n)
-  of mLeF64: result = newIntNodeT(ord(getFloat(a) <= getFloat(b)), n)
-  of mEqF64: result = newIntNodeT(ord(getFloat(a) == getFloat(b)), n)
-  of mLtStr: result = newIntNodeT(ord(getStr(a) < getStr(b)), n)
-  of mLeStr: result = newIntNodeT(ord(getStr(a) <= getStr(b)), n)
-  of mEqStr: result = newIntNodeT(ord(getStr(a) == getStr(b)), n)
+    result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n, g)
+  of mLtF64: result = newIntNodeT(ord(getFloat(a) < getFloat(b)), n, g)
+  of mLeF64: result = newIntNodeT(ord(getFloat(a) <= getFloat(b)), n, g)
+  of mEqF64: result = newIntNodeT(ord(getFloat(a) == getFloat(b)), n, g)
+  of mLtStr: result = newIntNodeT(ord(getStr(a) < getStr(b)), n, g)
+  of mLeStr: result = newIntNodeT(ord(getStr(a) <= getStr(b)), n, g)
+  of mEqStr: result = newIntNodeT(ord(getStr(a) == getStr(b)), n, g)
   of mLtU, mLtU64:
-    result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n)
+    result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n, g)
   of mLeU, mLeU64:
-    result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n)
-  of mBitandI, mAnd: result = newIntNodeT(a.getInt and b.getInt, n)
-  of mBitorI, mOr: result = newIntNodeT(getInt(a) or getInt(b), n)
-  of mBitxorI, mXor: result = newIntNodeT(a.getInt xor b.getInt, n)
-  of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n)
-  of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n)
-  of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n)
-  of mModU: result = foldModU(getInt(a), getInt(b), n)
-  of mDivU: result = foldDivU(getInt(a), getInt(b), n)
-  of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n)
-  of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n)
+    result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n, g)
+  of mBitandI, mAnd: result = newIntNodeT(a.getInt and b.getInt, n, g)
+  of mBitorI, mOr: result = newIntNodeT(getInt(a) or getInt(b), n, g)
+  of mBitxorI, mXor: result = newIntNodeT(a.getInt xor b.getInt, n, g)
+  of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n, g)
+  of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n, g)
+  of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n, g)
+  of mModU: result = foldModU(getInt(a), getInt(b), n, g)
+  of mDivU: result = foldDivU(getInt(a), getInt(b), n, g)
+  of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n, g)
+  of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n, g)
   of mLtSet:
-    result = newIntNodeT(ord(containsSets(a, b) and not equalSets(a, b)), n)
+    result = newIntNodeT(ord(containsSets(a, b) and not equalSets(a, b)), n, g)
   of mMulSet:
     result = nimsets.intersectSets(a, b)
     result.info = n.info
@@ -326,125 +320,125 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
   of mSymDiffSet:
     result = nimsets.symdiffSets(a, b)
     result.info = n.info
-  of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n)
-  of mInSet: result = newIntNodeT(ord(inSet(a, b)), n)
+  of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n, g)
+  of mInSet: result = newIntNodeT(ord(inSet(a, b)), n, g)
   of mRepr:
     # BUGFIX: we cannot eval mRepr here for reasons that I forgot.
     discard
-  of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n)
+  of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n, g)
   of mBoolToStr:
-    if getOrdValue(a) == 0: result = newStrNodeT("false", n)
-    else: result = newStrNodeT("true", n)
-  of mCopyStr: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b))), n)
+    if getOrdValue(a) == 0: result = newStrNodeT("false", n, g)
+    else: result = newStrNodeT("true", n, g)
+  of mCopyStr: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b))), n, g)
   of mCopyStrLast:
     result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)),
-                                           int(getOrdValue(c))), n)
-  of mFloatToStr: result = newStrNodeT($getFloat(a), n)
+                                           int(getOrdValue(c))), n, g)
+  of mFloatToStr: result = newStrNodeT($getFloat(a), n, g)
   of mCStrToStr, mCharToStr:
     if a.kind == nkBracket:
       var s = ""
       for b in a.sons:
         s.add b.getStrOrChar
-      result = newStrNodeT(s, n)
+      result = newStrNodeT(s, n, g)
     else:
-      result = newStrNodeT(getStrOrChar(a), n)
+      result = newStrNodeT(getStrOrChar(a), n, g)
   of mStrToStr: result = a
-  of mEnumToStr: result = newStrNodeT(ordinalValToString(a), n)
+  of mEnumToStr: result = newStrNodeT(ordinalValToString(a, g), n, g)
   of mArrToSeq:
     result = copyTree(a)
     result.typ = n.typ
   of mCompileOption:
-    result = newIntNodeT(ord(commands.testCompileOption(a.getStr, n.info)), n)
+    result = newIntNodeT(ord(commands.testCompileOption(g.config, a.getStr, n.info)), n, g)
   of mCompileOptionArg:
     result = newIntNodeT(ord(
-      testCompileOptionArg(getStr(a), getStr(b), n.info)), n)
+      testCompileOptionArg(g.config, getStr(a), getStr(b), n.info)), n, g)
   of mEqProc:
     result = newIntNodeT(ord(
-        exprStructuralEquivalent(a, b, strictSymEquality=true)), n)
+        exprStructuralEquivalent(a, b, strictSymEquality=true)), n, g)
   else: discard
 
-proc getConstIfExpr(c: PSym, n: PNode): PNode =
+proc getConstIfExpr(c: PSym, n: PNode; g: ModuleGraph): PNode =
   result = nil
   for i in countup(0, sonsLen(n) - 1):
     var it = n.sons[i]
     if it.len == 2:
-      var e = getConstExpr(c, it.sons[0])
+      var e = getConstExpr(c, it.sons[0], g)
       if e == nil: return nil
       if getOrdValue(e) != 0:
         if result == nil:
-          result = getConstExpr(c, it.sons[1])
+          result = getConstExpr(c, it.sons[1], g)
           if result == nil: return
     elif it.len == 1:
-      if result == nil: result = getConstExpr(c, it.sons[0])
-    else: internalError(it.info, "getConstIfExpr()")
+      if result == nil: result = getConstExpr(c, it.sons[0], g)
+    else: internalError(g.config, it.info, "getConstIfExpr()")
 
-proc leValueConv(a, b: PNode): bool =
+proc leValueConv*(a, b: PNode): bool =
   result = false
   case a.kind
   of nkCharLit..nkUInt64Lit:
     case b.kind
     of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal
     of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal).int
-    else: internalError(a.info, "leValueConv")
+    else: result = false #internalError(a.info, "leValueConv")
   of nkFloatLit..nkFloat128Lit:
     case b.kind
     of nkFloatLit..nkFloat128Lit: result = a.floatVal <= b.floatVal
     of nkCharLit..nkUInt64Lit: result = a.floatVal <= toFloat(int(b.intVal))
-    else: internalError(a.info, "leValueConv")
-  else: internalError(a.info, "leValueConv")
+    else: result = false # internalError(a.info, "leValueConv")
+  else: result = false # internalError(a.info, "leValueConv")
 
-proc magicCall(m: PSym, n: PNode): PNode =
+proc magicCall(m: PSym, n: PNode; g: ModuleGraph): PNode =
   if sonsLen(n) <= 1: return
 
   var s = n.sons[0].sym
-  var a = getConstExpr(m, n.sons[1])
+  var a = getConstExpr(m, n.sons[1], g)
   var b, c: PNode
   if a == nil: return
   if sonsLen(n) > 2:
-    b = getConstExpr(m, n.sons[2])
+    b = getConstExpr(m, n.sons[2], g)
     if b == nil: return
     if sonsLen(n) > 3:
-      c = getConstExpr(m, n.sons[3])
+      c = getConstExpr(m, n.sons[3], g)
       if c == nil: return
-  result = evalOp(s.magic, n, a, b, c)
-
-proc getAppType(n: PNode): PNode =
-  if gGlobalOptions.contains(optGenDynLib):
-    result = newStrNodeT("lib", n)
-  elif gGlobalOptions.contains(optGenStaticLib):
-    result = newStrNodeT("staticlib", n)
-  elif gGlobalOptions.contains(optGenGuiApp):
-    result = newStrNodeT("gui", n)
+  result = evalOp(s.magic, n, a, b, c, g)
+
+proc getAppType(n: PNode; g: ModuleGraph): PNode =
+  if g.config.globalOptions.contains(optGenDynLib):
+    result = newStrNodeT("lib", n, g)
+  elif g.config.globalOptions.contains(optGenStaticLib):
+    result = newStrNodeT("staticlib", n, g)
+  elif g.config.globalOptions.contains(optGenGuiApp):
+    result = newStrNodeT("gui", n, g)
   else:
-    result = newStrNodeT("console", n)
+    result = newStrNodeT("console", n, g)
 
-proc rangeCheck(n: PNode, value: BiggestInt) =
+proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) =
   var err = false
   if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}:
     err = value <% firstOrd(n.typ) or value >% lastOrd(n.typ, fixedUnsigned=true)
   else:
     err = value < firstOrd(n.typ) or value > lastOrd(n.typ)
   if err:
-    localError(n.info, errGenerated, "cannot convert " & $value &
+    localError(g.config, n.info, "cannot convert " & $value &
                                      " to " & typeToString(n.typ))
 
-proc foldConv*(n, a: PNode; check = false): PNode =
+proc foldConv*(n, a: PNode; g: ModuleGraph; check = false): PNode =
   # XXX range checks?
   case skipTypes(n.typ, abstractRange).kind
   of tyInt..tyInt64, tyUInt..tyUInt64:
     case skipTypes(a.typ, abstractRange).kind
     of tyFloat..tyFloat64:
-      result = newIntNodeT(int(getFloat(a)), n)
-    of tyChar: result = newIntNodeT(getOrdValue(a), n)
+      result = newIntNodeT(int(getFloat(a)), n, g)
+    of tyChar: result = newIntNodeT(getOrdValue(a), n, g)
     else:
       result = a
       result.typ = n.typ
     if check and result.kind in {nkCharLit..nkUInt64Lit}:
-      rangeCheck(n, result.intVal)
+      rangeCheck(n, result.intVal, g)
   of tyFloat..tyFloat64:
     case skipTypes(a.typ, abstractRange).kind
     of tyInt..tyInt64, tyEnum, tyBool, tyChar:
-      result = newFloatNodeT(toBiggestFloat(getOrdValue(a)), n)
+      result = newFloatNodeT(toBiggestFloat(getOrdValue(a)), n, g)
     else:
       result = a
       result.typ = n.typ
@@ -454,19 +448,19 @@ proc foldConv*(n, a: PNode; check = false): PNode =
     result = a
     result.typ = n.typ
 
-proc getArrayConstr(m: PSym, n: PNode): PNode =
+proc getArrayConstr(m: PSym, n: PNode; g: ModuleGraph): PNode =
   if n.kind == nkBracket:
     result = n
   else:
-    result = getConstExpr(m, n)
+    result = getConstExpr(m, n, g)
     if result == nil: result = n
 
-proc foldArrayAccess(m: PSym, n: PNode): PNode =
-  var x = getConstExpr(m, n.sons[0])
+proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
+  var x = getConstExpr(m, n.sons[0], g)
   if x == nil or x.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyTypeDesc:
     return
 
-  var y = getConstExpr(m, n.sons[1])
+  var y = getConstExpr(m, n.sons[1], g)
   if y == nil: return
 
   var idx = getOrdValue(y)
@@ -476,24 +470,24 @@ proc foldArrayAccess(m: PSym, n: PNode): PNode =
       result = x.sons[int(idx)]
       if result.kind == nkExprColonExpr: result = result.sons[1]
     else:
-      localError(n.info, errIndexOutOfBounds)
+      localError(g.config, n.info, "index out of bounds: " & $n)
   of nkBracket:
     idx = idx - x.typ.firstOrd
     if idx >= 0 and idx < x.len: result = x.sons[int(idx)]
-    else: localError(n.info, errIndexOutOfBounds)
+    else: localError(g.config, n.info, "index out of bounds: " & $n)
   of nkStrLit..nkTripleStrLit:
     result = newNodeIT(nkCharLit, x.info, n.typ)
     if idx >= 0 and idx < len(x.strVal):
       result.intVal = ord(x.strVal[int(idx)])
-    elif idx == len(x.strVal):
+    elif idx == len(x.strVal) and optLaxStrings in g.config.options:
       discard
     else:
-      localError(n.info, errIndexOutOfBounds)
+      localError(g.config, n.info, "index out of bounds: " & $n)
   else: discard
 
-proc foldFieldAccess(m: PSym, n: PNode): PNode =
+proc foldFieldAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
   # a real field access; proc calls have already been transformed
-  var x = getConstExpr(m, n.sons[0])
+  var x = getConstExpr(m, n.sons[0], g)
   if x == nil or x.kind notin {nkObjConstr, nkPar, nkTupleConstr}: return
 
   var field = n.sons[1].sym
@@ -507,13 +501,13 @@ proc foldFieldAccess(m: PSym, n: PNode): PNode =
     if it.sons[0].sym.name.id == field.name.id:
       result = x.sons[i].sons[1]
       return
-  localError(n.info, errFieldXNotFound, field.name.s)
+  localError(g.config, n.info, "field not found: " & field.name.s)
 
-proc foldConStrStr(m: PSym, n: PNode): PNode =
+proc foldConStrStr(m: PSym, n: PNode; g: ModuleGraph): PNode =
   result = newNodeIT(nkStrLit, n.info, n.typ)
   result.strVal = ""
   for i in countup(1, sonsLen(n) - 1):
-    let a = getConstExpr(m, n.sons[i])
+    let a = getConstExpr(m, n.sons[i], g)
     if a == nil: return nil
     result.strVal.add(getStrOrChar(a))
 
@@ -525,7 +519,7 @@ proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode =
   else:
     result.typ = s.typ
 
-proc getConstExpr(m: PSym, n: PNode): PNode =
+proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
   result = nil
 
   proc getSrcTimestamp(): DateTime =
@@ -545,32 +539,35 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
     var s = n.sym
     case s.kind
     of skEnumField:
-      result = newIntNodeT(s.position, n)
+      result = newIntNodeT(s.position, n, g)
     of skConst:
       case s.magic
-      of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n)
+      of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n, g)
       of mCompileDate: result = newStrNodeT(format(getSrcTimestamp(),
-                                                   "yyyy-MM-dd"), n)
+                                                   "yyyy-MM-dd"), n, g)
       of mCompileTime: result = newStrNodeT(format(getSrcTimestamp(),
-                                                   "HH:mm:ss"), n)
-      of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n)
-      of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n)
-      of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n)
-      of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[platform.hostOS].name), n)
-      of mBuildCPU: result = newStrNodeT(platform.CPU[platform.hostCPU].name.toLowerAscii, n)
-      of mAppType: result = getAppType(n)
-      of mNaN: result = newFloatNodeT(NaN, n)
-      of mInf: result = newFloatNodeT(Inf, n)
-      of mNegInf: result = newFloatNodeT(NegInf, n)
+                                                   "HH:mm:ss"), n, g)
+      of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n, g)
+      of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n, g)
+      of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n, g)
+      of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[platform.hostOS].name), n, g)
+      of mBuildCPU: result = newStrNodeT(platform.CPU[platform.hostCPU].name.toLowerAscii, n, g)
+      of mAppType: result = getAppType(n, g)
+      of mNaN: result = newFloatNodeT(NaN, n, g)
+      of mInf: result = newFloatNodeT(Inf, n, g)
+      of mNegInf: result = newFloatNodeT(NegInf, n, g)
       of mIntDefine:
-        if isDefined(s.name):
-          result = newIntNodeT(lookupSymbol(s.name).parseInt, n)
+        if isDefined(g.config, s.name.s):
+          try:
+            result = newIntNodeT(g.config.symbols[s.name.s].parseInt, n, g)
+          except ValueError:
+            localError(g.config, n.info, "expression is not an integer literal")
       of mStrDefine:
-        if isDefined(s.name):
-          result = newStrNodeT(lookupSymbol(s.name), n)
+        if isDefined(g.config, s.name.s):
+          result = newStrNodeT(g.config.symbols[s.name.s], n, g)
       else:
         result = copyTree(s.ast)
-    of {skProc, skFunc, skMethod}:
+    of skProc, skFunc, skMethod:
       result = n
     of skType:
       # XXX gensym'ed symbols can come here and cannot be resolved. This is
@@ -590,7 +587,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
   of nkCharLit..nkNilLit:
     result = copyNode(n)
   of nkIfExpr:
-    result = getConstIfExpr(m, n)
+    result = getConstIfExpr(m, n, g)
   of nkCallKinds:
     if n.sons[0].kind != nkSym: return
     var s = n.sons[0].sym
@@ -603,68 +600,67 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
       of mSizeOf:
         var a = n.sons[1]
         if computeSize(a.typ) < 0:
-          localError(a.info, errCannotEvalXBecauseIncompletelyDefined,
-                     "sizeof")
+          localError(g.config, a.info, "cannot evaluate 'sizeof' because its type is not defined completely")
           result = nil
         elif skipTypes(a.typ, typedescInst+{tyRange}).kind in
              IntegralTypes+NilableTypes+{tySet}:
           #{tyArray,tyObject,tyTuple}:
-          result = newIntNodeT(getSize(a.typ), n)
+          result = newIntNodeT(getSize(a.typ), n, g)
         else:
           result = nil
           # XXX: size computation for complex types is still wrong
       of mLow:
-        result = newIntNodeT(firstOrd(n.sons[1].typ), n)
+        result = newIntNodeT(firstOrd(n.sons[1].typ), n, g)
       of mHigh:
         if skipTypes(n.sons[1].typ, abstractVar).kind notin
             {tySequence, tyString, tyCString, tyOpenArray, tyVarargs}:
-          result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n)
+          result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n, g)
         else:
-          var a = getArrayConstr(m, n.sons[1])
+          var a = getArrayConstr(m, n.sons[1], g)
           if a.kind == nkBracket:
             # we can optimize it away:
-            result = newIntNodeT(sonsLen(a)-1, n)
+            result = newIntNodeT(sonsLen(a)-1, n, g)
       of mLengthOpenArray:
-        var a = getArrayConstr(m, n.sons[1])
+        var a = getArrayConstr(m, n.sons[1], g)
         if a.kind == nkBracket:
           # we can optimize it away! This fixes the bug ``len(134)``.
-          result = newIntNodeT(sonsLen(a), n)
+          result = newIntNodeT(sonsLen(a), n, g)
         else:
-          result = magicCall(m, n)
+          result = magicCall(m, n, g)
       of mLengthArray:
         # It doesn't matter if the argument is const or not for mLengthArray.
         # This fixes bug #544.
-        result = newIntNodeT(lengthOrd(n.sons[1].typ), n)
+        result = newIntNodeT(lengthOrd(n.sons[1].typ), n, g)
       of mAstToStr:
-        result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
+        result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, g)
       of mConStrStr:
-        result = foldConStrStr(m, n)
+        result = foldConStrStr(m, n, g)
       of mIs:
-        let a = getConstExpr(m, n[1])
+        let a = getConstExpr(m, n[1], g)
         if a != nil and a.kind == nkSym and a.sym.kind == skType:
           result = evalIs(n, a)
       else:
-        result = magicCall(m, n)
+        result = magicCall(m, n, g)
     except OverflowError:
-      localError(n.info, errOverOrUnderflow)
+      localError(g.config, n.info, "over- or underflow")
     except DivByZeroError:
-      localError(n.info, errConstantDivisionByZero)
+      localError(g.config, n.info, "division by zero")
   of nkAddr:
-    var a = getConstExpr(m, n.sons[0])
+    var a = getConstExpr(m, n.sons[0], g)
     if a != nil:
       result = n
       n.sons[0] = a
   of nkBracket:
     result = copyTree(n)
     for i in countup(0, sonsLen(n) - 1):
-      var a = getConstExpr(m, n.sons[i])
+      var a = getConstExpr(m, n.sons[i], g)
       if a == nil: return nil
       result.sons[i] = a
     incl(result.flags, nfAllConst)
   of nkRange:
-    var a = getConstExpr(m, n.sons[0])
+    var a = getConstExpr(m, n.sons[0], g)
     if a == nil: return
-    var b = getConstExpr(m, n.sons[1])
+    var b = getConstExpr(m, n.sons[1], g)
     if b == nil: return
     result = copyNode(n)
     addSon(result, a)
@@ -672,7 +668,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
   of nkCurly:
     result = copyTree(n)
     for i in countup(0, sonsLen(n) - 1):
-      var a = getConstExpr(m, n.sons[i])
+      var a = getConstExpr(m, n.sons[i], g)
       if a == nil: return nil
       result.sons[i] = a
     incl(result.flags, nfAllConst)
@@ -688,45 +684,45 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
     result = copyTree(n)
     if (sonsLen(n) > 0) and (n.sons[0].kind == nkExprColonExpr):
       for i in countup(0, sonsLen(n) - 1):
-        var a = getConstExpr(m, n.sons[i].sons[1])
+        var a = getConstExpr(m, n.sons[i].sons[1], g)
         if a == nil: return nil
         result.sons[i].sons[1] = a
     else:
       for i in countup(0, sonsLen(n) - 1):
-        var a = getConstExpr(m, n.sons[i])
+        var a = getConstExpr(m, n.sons[i], g)
         if a == nil: return nil
         result.sons[i] = a
     incl(result.flags, nfAllConst)
   of nkChckRangeF, nkChckRange64, nkChckRange:
-    var a = getConstExpr(m, n.sons[0])
+    var a = getConstExpr(m, n.sons[0], g)
     if a == nil: return
     if leValueConv(n.sons[1], a) and leValueConv(a, n.sons[2]):
       result = a              # a <= x and x <= b
       result.typ = n.typ
     else:
-      localError(n.info, errGenerated, `%`(
-          msgKindToString(errIllegalConvFromXtoY),
-          [typeToString(n.sons[0].typ), typeToString(n.typ)]))
+      localError(g.config, n.info,
+        "conversion from $1 to $2 is invalid" %
+          [typeToString(n.sons[0].typ), typeToString(n.typ)])
   of nkStringToCString, nkCStringToString:
-    var a = getConstExpr(m, n.sons[0])
+    var a = getConstExpr(m, n.sons[0], g)
     if a == nil: return
     result = a
     result.typ = n.typ
   of nkHiddenStdConv, nkHiddenSubConv, nkConv:
-    var a = getConstExpr(m, n.sons[1])
+    var a = getConstExpr(m, n.sons[1], g)
     if a == nil: return
-    result = foldConv(n, a, check=n.kind == nkHiddenStdConv)
+    result = foldConv(n, a, g, check=n.kind == nkHiddenStdConv)
   of nkCast:
-    var a = getConstExpr(m, n.sons[1])
+    var a = getConstExpr(m, n.sons[1], g)
     if a == nil: return
     if n.typ != nil and n.typ.kind in NilableTypes:
       # we allow compile-time 'cast' for pointer types:
       result = a
       result.typ = n.typ
-  of nkBracketExpr: result = foldArrayAccess(m, n)
-  of nkDotExpr: result = foldFieldAccess(m, n)
+  of nkBracketExpr: result = foldArrayAccess(m, n, g)
+  of nkDotExpr: result = foldFieldAccess(m, n, g)
   of nkStmtListExpr:
     if n.len == 2 and n[0].kind == nkComesFrom:
-      result = getConstExpr(m, n[1])
+      result = getConstExpr(m, n[1], g)
   else:
     discard
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index 16da06952..8f06e748e 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -17,13 +17,13 @@
 
 # included from sem.nim
 
-proc getIdentNode(n: PNode): PNode =
+proc getIdentNode(c: PContext; n: PNode): PNode =
   case n.kind
-  of nkPostfix: result = getIdentNode(n.sons[1])
-  of nkPragmaExpr: result = getIdentNode(n.sons[0])
+  of nkPostfix: result = getIdentNode(c, n.sons[1])
+  of nkPragmaExpr: result = getIdentNode(c, n.sons[0])
   of nkIdent, nkAccQuoted, nkSym: result = n
   else:
-    illFormedAst(n)
+    illFormedAst(n, c.config)
     result = n
 
 type
@@ -103,8 +103,8 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
 proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
             ctx: var GenericCtx): PNode =
   result = n
-  let ident = considerQuotedIdent(n)
-  var s = searchInScopes(c, ident).skipAlias(n)
+  let ident = considerQuotedIdent(c.config, n)
+  var s = searchInScopes(c, ident).skipAlias(n, c.config)
   if s == nil:
     s = strTableGet(c.pureEnumFields, ident)
     if s != nil and contains(c.ambiguousSymbols, s.id):
@@ -140,8 +140,8 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
     n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx)
     result = n
     let n = n[1]
-    let ident = considerQuotedIdent(n)
-    var s = searchInScopes(c, ident).skipAlias(n)
+    let ident = considerQuotedIdent(c.config, n)
+    var s = searchInScopes(c, ident).skipAlias(n, c.config)
     if s != nil and s.kind in routineKinds:
       isMacro = s.kind in {skTemplate, skMacro}
       if withinBind in flags:
@@ -158,7 +158,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
           result = newDot(result, syms)
 
 proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
-  let s = newSymS(skUnknown, getIdentNode(n), c)
+  let s = newSymS(skUnknown, getIdentNode(c, n), c)
   addPrelimDecl(c, s)
   styleCheckDef(n.info, s, kind)
 
@@ -169,7 +169,7 @@ proc semGenericStmt(c: PContext, n: PNode,
   when defined(nimsuggest):
     if withinTypeDesc in flags: inc c.inTypeContext
 
-  #if gCmd == cmdIdeTools: suggestStmt(c, n)
+  #if conf.cmd == cmdIdeTools: suggestStmt(c, n)
   semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
 
   case n.kind
@@ -201,13 +201,13 @@ proc semGenericStmt(c: PContext, n: PNode,
     result = semMixinStmt(c, n, ctx.toMixin)
   of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit:
     # check if it is an expression macro:
-    checkMinSonsLen(n, 1)
+    checkMinSonsLen(n, 1, c.config)
     let fn = n.sons[0]
     var s = qualifiedLookUp(c, fn, {})
     if  s == nil and
         {withinMixin, withinConcept}*flags == {} and
         fn.kind in {nkIdent, nkAccQuoted} and
-        considerQuotedIdent(fn).id notin ctx.toMixin:
+        considerQuotedIdent(c.config, fn).id notin ctx.toMixin:
       errorUndeclaredIdentifier(c, n.info, fn.renderTree)
 
     var first = int ord(withinConcept in flags)
@@ -285,7 +285,7 @@ proc semGenericStmt(c: PContext, n: PNode,
     withBracketExpr ctx, n.sons[0]:
       result = semGenericStmt(c, result, flags, ctx)
   of nkAsgn, nkFastAsgn:
-    checkSonsLen(n, 2)
+    checkSonsLen(n, 2, c.config)
     let a = n.sons[0]
     let b = n.sons[1]
 
@@ -323,7 +323,7 @@ proc semGenericStmt(c: PContext, n: PNode,
     n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx)
     for i in countup(1, sonsLen(n)-1):
       var a = n.sons[i]
-      checkMinSonsLen(a, 1)
+      checkMinSonsLen(a, 1, c.config)
       var L = sonsLen(a)
       for j in countup(0, L-2):
         a.sons[j] = semGenericStmt(c, a.sons[j], flags, ctx)
@@ -340,23 +340,23 @@ proc semGenericStmt(c: PContext, n: PNode,
     closeScope(c)
     closeScope(c)
   of nkBlockStmt, nkBlockExpr, nkBlockType:
-    checkSonsLen(n, 2)
+    checkSonsLen(n, 2, c.config)
     openScope(c)
     if n.sons[0].kind != nkEmpty:
       addTempDecl(c, n.sons[0], skLabel)
     n.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
     closeScope(c)
   of nkTryStmt:
-    checkMinSonsLen(n, 2)
+    checkMinSonsLen(n, 2, c.config)
     n.sons[0] = semGenericStmtScope(c, n.sons[0], flags, ctx)
     for i in countup(1, sonsLen(n)-1):
       var a = n.sons[i]
-      checkMinSonsLen(a, 1)
+      checkMinSonsLen(a, 1, c.config)
       var L = sonsLen(a)
       openScope(c)
       for j in countup(0, L-2):
         if a.sons[j].isInfixAs():
-          addTempDecl(c, getIdentNode(a.sons[j][2]), skLet)
+          addTempDecl(c, getIdentNode(c, a.sons[j][2]), skLet)
           a.sons[j].sons[1] = semGenericStmt(c, a.sons[j][1], flags+{withinTypeDesc}, ctx)
         else:
           a.sons[j] = semGenericStmt(c, a.sons[j], flags+{withinTypeDesc}, ctx)
@@ -367,44 +367,44 @@ proc semGenericStmt(c: PContext, n: PNode,
     for i in countup(0, sonsLen(n) - 1):
       var a = n.sons[i]
       if a.kind == nkCommentStmt: continue
-      if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a)
-      checkMinSonsLen(a, 3)
+      if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a, c.config)
+      checkMinSonsLen(a, 3, c.config)
       var L = sonsLen(a)
       a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
       a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
       for j in countup(0, L-3):
-        addTempDecl(c, getIdentNode(a.sons[j]), skVar)
+        addTempDecl(c, getIdentNode(c, a.sons[j]), skVar)
   of nkGenericParams:
     for i in countup(0, sonsLen(n) - 1):
       var a = n.sons[i]
-      if (a.kind != nkIdentDefs): illFormedAst(a)
-      checkMinSonsLen(a, 3)
+      if (a.kind != nkIdentDefs): illFormedAst(a, c.config)
+      checkMinSonsLen(a, 3, c.config)
       var L = sonsLen(a)
       a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
       # do not perform symbol lookup for default expressions
       for j in countup(0, L-3):
-        addTempDecl(c, getIdentNode(a.sons[j]), skType)
+        addTempDecl(c, getIdentNode(c, a.sons[j]), skType)
   of nkConstSection:
     for i in countup(0, sonsLen(n) - 1):
       var a = n.sons[i]
       if a.kind == nkCommentStmt: continue
-      if (a.kind != nkConstDef): illFormedAst(a)
-      checkSonsLen(a, 3)
-      addTempDecl(c, getIdentNode(a.sons[0]), skConst)
+      if (a.kind != nkConstDef): illFormedAst(a, c.config)
+      checkSonsLen(a, 3, c.config)
+      addTempDecl(c, getIdentNode(c, a.sons[0]), skConst)
       a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx)
       a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx)
   of nkTypeSection:
     for i in countup(0, sonsLen(n) - 1):
       var a = n.sons[i]
       if a.kind == nkCommentStmt: continue
-      if (a.kind != nkTypeDef): illFormedAst(a)
-      checkSonsLen(a, 3)
-      addTempDecl(c, getIdentNode(a.sons[0]), skType)
+      if (a.kind != nkTypeDef): illFormedAst(a, c.config)
+      checkSonsLen(a, 3, c.config)
+      addTempDecl(c, getIdentNode(c, a.sons[0]), skType)
     for i in countup(0, sonsLen(n) - 1):
       var a = n.sons[i]
       if a.kind == nkCommentStmt: continue
-      if (a.kind != nkTypeDef): illFormedAst(a)
-      checkSonsLen(a, 3)
+      if (a.kind != nkTypeDef): illFormedAst(a, c.config)
+      checkSonsLen(a, 3, c.config)
       if a.sons[1].kind != nkEmpty:
         openScope(c)
         a.sons[1] = semGenericStmt(c, a.sons[1], flags, ctx)
@@ -421,28 +421,28 @@ proc semGenericStmt(c: PContext, n: PNode,
         case n.sons[i].kind
         of nkEnumFieldDef: a = n.sons[i].sons[0]
         of nkIdent: a = n.sons[i]
-        else: illFormedAst(n)
-        addDecl(c, newSymS(skUnknown, getIdentNode(a), c))
+        else: illFormedAst(n, c.config)
+        addDecl(c, newSymS(skUnknown, getIdentNode(c, a), c))
   of nkObjectTy, nkTupleTy, nkTupleClassTy:
     discard
   of nkFormalParams:
-    checkMinSonsLen(n, 1)
+    checkMinSonsLen(n, 1, c.config)
     if n.sons[0].kind != nkEmpty:
       n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
     for i in countup(1, sonsLen(n) - 1):
       var a = n.sons[i]
-      if (a.kind != nkIdentDefs): illFormedAst(a)
-      checkMinSonsLen(a, 3)
+      if (a.kind != nkIdentDefs): illFormedAst(a, c.config)
+      checkMinSonsLen(a, 3, c.config)
       var L = sonsLen(a)
       a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
       a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
       for j in countup(0, L-3):
-        addTempDecl(c, getIdentNode(a.sons[j]), skParam)
+        addTempDecl(c, getIdentNode(c, a.sons[j]), skParam)
   of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
      nkFuncDef, nkIteratorDef, nkLambdaKinds:
-    checkSonsLen(n, bodyPos + 1)
+    checkSonsLen(n, bodyPos + 1, c.config)
     if n.sons[namePos].kind != nkEmpty:
-      addTempDecl(c, getIdentNode(n.sons[0]), skProc)
+      addTempDecl(c, getIdentNode(c, n.sons[0]), skProc)
     openScope(c)
     n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos],
                                               flags, ctx)
@@ -463,7 +463,7 @@ proc semGenericStmt(c: PContext, n: PNode,
     closeScope(c)
   of nkPragma, nkPragmaExpr: discard
   of nkExprColonExpr, nkExprEqExpr:
-    checkMinSonsLen(n, 2)
+    checkMinSonsLen(n, 2, c.config)
     result.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
   else:
     for i in countup(0, sonsLen(n) - 1):
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 0513e2395..a5f0ca7d8 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -54,10 +54,13 @@ proc pushProcCon*(c: PContext; owner: PSym) =
   rawPushProcCon(c, owner)
   rawHandleSelf(c, owner)
 
+const
+  errCannotInstantiateX = "cannot instantiate: '$1'"
+
 iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym =
-  internalAssert n.kind == nkGenericParams
+  internalAssert c.config, n.kind == nkGenericParams
   for i, a in n.pairs:
-    internalAssert a.kind == nkSym
+    internalAssert c.config, a.kind == nkSym
     var q = a.sym
     if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic}+tyTypeClasses:
       continue
@@ -71,10 +74,10 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym
         # later by semAsgn in return type inference scenario
         t = q.typ
       else:
-        localError(a.info, errCannotInstantiateX, s.name.s)
+        localError(c.config, a.info, errCannotInstantiateX % s.name.s)
         t = errorType(c)
     elif t.kind == tyGenericParam:
-      localError(a.info, errCannotInstantiateX, q.name.s)
+      localError(c.config, a.info, errCannotInstantiateX % q.name.s)
       t = errorType(c)
     elif t.kind == tyGenericInvocation:
       #t = instGenericContainer(c, a, t)
@@ -145,7 +148,7 @@ proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
     freshGenSyms(b, result, orig, symMap)
     b = semProcBody(c, b)
     b = hloBody(c, b)
-    n.sons[bodyPos] = transformBody(c.module, c.features, b, result)
+    n.sons[bodyPos] = transformBody(c.graph, c.module, b, result)
     #echo "code instantiated ", result.name.s
     excl(result.flags, sfForward)
     dec c.inGenericInst
@@ -174,7 +177,7 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
 
 proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
                           allowMetaTypes = false): PType =
-  internalAssert header.kind == tyGenericInvocation
+  internalAssert c.config, header.kind == tyGenericInvocation
 
   var
     typeMap: LayeredIdTable
@@ -199,7 +202,7 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
     var param: PSym
 
     template paramSym(kind): untyped =
-        newSym(kind, genParam.sym.name, genericTyp.sym, genParam.sym.info)
+      newSym(kind, genParam.sym.name, genericTyp.sym, genParam.sym.info)
 
     if genParam.kind == tyStatic:
       param = paramSym skConst
@@ -233,14 +236,12 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
   # at this point semtypinst have to become part of sem, because it
   # will need to use openScope, addDecl, etc.
   #addDecl(c, prc)
-
   pushInfoContext(info)
   var typeMap = initLayeredTypeMap(pt)
   var cl = initTypeVars(c, addr(typeMap), info, nil)
   var result = instCopyType(cl, prc.typ)
   let originalParams = result.n
   result.n = originalParams.shallowCopy
-
   for i in 1 ..< result.len:
     # twrong_field_caching requires these 'resetIdTable' calls:
     if i > 1:
@@ -248,7 +249,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
       resetIdTable(cl.localCache)
     result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
     propagateToOwner(result, result.sons[i])
-    internalAssert originalParams[i].kind == nkSym
+    internalAssert c.config, originalParams[i].kind == nkSym
     when true:
       let oldParam = originalParams[i].sym
       let param = copySym(oldParam)
@@ -285,9 +286,9 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   ## The `pt` parameter is a type-unsafe mapping table used to link generic
   ## parameters to their concrete types within the generic instance.
   # no need to instantiate generic templates/macros:
-  internalAssert fn.kind notin {skMacro, skTemplate}
+  internalAssert c.config, fn.kind notin {skMacro, skTemplate}
   # generates an instantiated proc
-  if c.instCounter > 1000: internalError(fn.ast.info, "nesting too deep")
+  if c.instCounter > 1000: internalError(c.config, fn.ast.info, "nesting too deep")
   inc(c.instCounter)
   # careful! we copy the whole AST including the possibly nil body!
   var n = copyTree(fn.ast)
@@ -306,7 +307,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
 
   openScope(c)
   let gp = n.sons[genericParamsPos]
-  internalAssert gp.kind != nkEmpty
+  internalAssert c.config, gp.kind != nkEmpty
   n.sons[namePos] = newSymNode(result)
   pushInfoContext(info)
   var entry = TInstantiation.new
diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim
index f6df67441..02c56c035 100644
--- a/compiler/semmacrosanity.nim
+++ b/compiler/semmacrosanity.nim
@@ -10,7 +10,7 @@
 ## Implements type sanity checking for ASTs resulting from macros. Lots of
 ## room for improvement here.
 
-import ast, astalgo, msgs, types
+import ast, astalgo, msgs, types, options
 
 proc ithField(n: PNode, field: var int): PSym =
   result = nil
@@ -20,7 +20,7 @@ proc ithField(n: PNode, field: var int): PSym =
       result = ithField(n.sons[i], field)
       if result != nil: return
   of nkRecCase:
-    if n.sons[0].kind != nkSym: internalError(n.info, "ithField")
+    if n.sons[0].kind != nkSym: return
     result = ithField(n.sons[0], field)
     if result != nil: return
     for i in countup(1, sonsLen(n) - 1):
@@ -28,13 +28,13 @@ proc ithField(n: PNode, field: var int): PSym =
       of nkOfBranch, nkElse:
         result = ithField(lastSon(n.sons[i]), field)
         if result != nil: return
-      else: internalError(n.info, "ithField(record case branch)")
+      else: discard
   of nkSym:
     if field == 0: result = n.sym
     else: dec(field)
   else: discard
 
-proc annotateType*(n: PNode, t: PType) =
+proc annotateType*(n: PNode, t: PType; conf: ConfigRef) =
   let x = t.skipTypes(abstractInst+{tyRange})
   # Note: x can be unequal to t and we need to be careful to use 't'
   # to not to skip tyGenericInst
@@ -46,50 +46,50 @@ proc annotateType*(n: PNode, t: PType) =
       var j = i-1
       let field = x.n.ithField(j)
       if field.isNil:
-        globalError n.info, "invalid field at index " & $i
+        globalError conf, n.info, "invalid field at index " & $i
       else:
-        internalAssert(n.sons[i].kind == nkExprColonExpr)
-        annotateType(n.sons[i].sons[1], field.typ)
+        internalAssert(conf, n.sons[i].kind == nkExprColonExpr)
+        annotateType(n.sons[i].sons[1], field.typ, conf)
   of nkPar, nkTupleConstr:
     if x.kind == tyTuple:
       n.typ = t
       for i in 0 ..< n.len:
-        if i >= x.len: globalError n.info, "invalid field at index " & $i
-        else: annotateType(n.sons[i], x.sons[i])
+        if i >= x.len: globalError conf, n.info, "invalid field at index " & $i
+        else: annotateType(n.sons[i], x.sons[i], conf)
     elif x.kind == tyProc and x.callConv == ccClosure:
       n.typ = t
     else:
-      globalError(n.info, "() must have a tuple type")
+      globalError(conf, n.info, "() must have a tuple type")
   of nkBracket:
     if x.kind in {tyArray, tySequence, tyOpenArray}:
       n.typ = t
-      for m in n: annotateType(m, x.elemType)
+      for m in n: annotateType(m, x.elemType, conf)
     else:
-      globalError(n.info, "[] must have some form of array type")
+      globalError(conf, n.info, "[] must have some form of array type")
   of nkCurly:
     if x.kind in {tySet}:
       n.typ = t
-      for m in n: annotateType(m, x.elemType)
+      for m in n: annotateType(m, x.elemType, conf)
     else:
-      globalError(n.info, "{} must have the set type")
+      globalError(conf, n.info, "{} must have the set type")
   of nkFloatLit..nkFloat128Lit:
     if x.kind in {tyFloat..tyFloat128}:
       n.typ = t
     else:
-      globalError(n.info, "float literal must have some float type")
+      globalError(conf, n.info, "float literal must have some float type")
   of nkCharLit..nkUInt64Lit:
     if x.kind in {tyInt..tyUInt64, tyBool, tyChar, tyEnum}:
       n.typ = t
     else:
-      globalError(n.info, "integer literal must have some int type")
+      globalError(conf, n.info, "integer literal must have some int type")
   of nkStrLit..nkTripleStrLit:
     if x.kind in {tyString, tyCString}:
       n.typ = t
     else:
-      globalError(n.info, "string literal must be of some string type")
+      globalError(conf, n.info, "string literal must be of some string type")
   of nkNilLit:
     if x.kind in NilableTypes:
       n.typ = t
     else:
-      globalError(n.info, "nil literal must be of some pointer type")
+      globalError(conf, n.info, "nil literal must be of some pointer type")
   else: discard
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index e6e29b4d3..8515e971d 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -16,7 +16,7 @@ proc semAddr(c: PContext; n: PNode; isUnsafeAddr=false): PNode =
   if x.kind == nkSym:
     x.sym.flags.incl(sfAddrTaken)
   if isAssignable(c, x, isUnsafeAddr) notin {arLValue, arLocalLValue}:
-    localError(n.info, errExprHasNoAddress)
+    localError(c.config, n.info, errExprHasNoAddress)
   result.add x
   result.typ = makePtrType(c, x.typ)
 
@@ -43,7 +43,7 @@ proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
     let x = copyTree(n)
     x.sons[0] = newIdentNode(getIdent"[]", n.info)
     bracketNotFoundError(c, x)
-    #localError(n.info, "could not resolve: " & $n)
+    #localError(c.config, n.info, "could not resolve: " & $n)
     result = n
 
 proc semArrPut(c: PContext; n: PNode; flags: TExprFlags): PNode =
@@ -64,24 +64,24 @@ 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(ord(r), n)
+  result = newIntNodeT(ord(r), n, c.graph)
 
 proc expectIntLit(c: PContext, n: PNode): int =
   let x = c.semConstExpr(c, n)
   case x.kind
   of nkIntLit..nkInt64Lit: result = int(x.intVal)
-  else: localError(n.info, errIntLiteralExpected)
+  else: localError(c.config, n.info, errIntLiteralExpected)
 
 proc semInstantiationInfo(c: PContext, n: PNode): PNode =
   result = newNodeIT(nkTupleConstr, n.info, n.typ)
   let idx = expectIntLit(c, n.sons[1])
   let useFullPaths = expectIntLit(c, n.sons[2])
   let info = getInfoContext(idx)
-  var filename = newNodeIT(nkStrLit, n.info, getSysType(tyString))
+  var filename = newNodeIT(nkStrLit, n.info, getSysType(c.graph, n.info, tyString))
   filename.strVal = if useFullPaths != 0: info.toFullPath else: info.toFilename
-  var line = newNodeIT(nkIntLit, n.info, getSysType(tyInt))
+  var line = newNodeIT(nkIntLit, n.info, getSysType(c.graph, n.info, tyInt))
   line.intVal = toLinenumber(info)
-  var column = newNodeIT(nkIntLit, n.info, getSysType(tyInt))
+  var column = newNodeIT(nkIntLit, n.info, getSysType(c.graph, n.info, tyInt))
   column.intVal = toColumn(info)
   result.add(filename)
   result.add(line)
@@ -110,10 +110,10 @@ proc uninstantiate(t: PType): PType =
     of tyCompositeTypeClass: uninstantiate t.sons[1]
     else: t
 
-proc evalTypeTrait(traitCall: PNode, operand: PType, context: PSym): PNode =
+proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym): PNode =
   const skippedTypes = {tyTypeDesc, tyAlias, tySink}
   let trait = traitCall[0]
-  internalAssert trait.kind == nkSym
+  internalAssert c.config, trait.kind == nkSym
   var operand = operand.skipTypes(skippedTypes)
 
   template operand2: PType =
@@ -140,7 +140,7 @@ proc evalTypeTrait(traitCall: PNode, operand: PType, context: PSym): PNode =
   of "genericHead":
     var res = uninstantiate(operand)
     if res == operand and res.kind notin tyMagicGenerics:
-      localError(traitCall.info,
+      localError(c.config, traitCall.info,
         "genericHead expects a generic type. The given type was " &
         typeToString(operand))
       return newType(tyError, context).toNode(traitCall.info)
@@ -151,19 +151,19 @@ proc evalTypeTrait(traitCall: PNode, operand: PType, context: PSym): PNode =
     let t = operand.skipTypes({tyVar, tyLent, tyGenericInst, tyAlias, tySink, tyInferred})
     let complexObj = containsGarbageCollectedRef(t) or
                      hasDestructor(t)
-    result = newIntNodeT(ord(not complexObj), traitCall)
+    result = newIntNodeT(ord(not complexObj), traitCall, c.graph)
   else:
-    localError(traitCall.info, "unknown trait")
+    localError(c.config, traitCall.info, "unknown trait")
     result = emptyNode
 
 proc semTypeTraits(c: PContext, n: PNode): PNode =
-  checkMinSonsLen(n, 2)
+  checkMinSonsLen(n, 2, c.config)
   let t = n.sons[1].typ
-  internalAssert t != nil and t.kind == tyTypeDesc
+  internalAssert c.config, t != nil and t.kind == tyTypeDesc
   if t.sonsLen > 0:
     # This is either a type known to sem or a typedesc
     # param to a regular proc (again, known at instantiation)
-    result = evalTypeTrait(n, t, getCurrOwner(c))
+    result = evalTypeTrait(c, n, t, getCurrOwner(c))
   else:
     # a typedesc variable, pass unmodified to evals
     result = n
@@ -176,7 +176,7 @@ proc semOrd(c: PContext, n: PNode): PNode =
   elif parType.kind == tySet:
     result.typ = makeRangeType(c, firstOrd(parType), lastOrd(parType), n.info)
   else:
-    localError(n.info, errOrdinalTypeExpected)
+    localError(c.config, n.info, errOrdinalTypeExpected)
     result.typ = errorType(c)
 
 proc semBindSym(c: PContext, n: PNode): PNode =
@@ -185,13 +185,13 @@ proc semBindSym(c: PContext, n: PNode): PNode =
 
   let sl = semConstExpr(c, n.sons[1])
   if sl.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
-    localError(n.sons[1].info, errStringLiteralExpected)
+    localError(c.config, n.sons[1].info, errStringLiteralExpected)
     return errorNode(c, n)
 
   let isMixin = semConstExpr(c, n.sons[2])
   if isMixin.kind != nkIntLit or isMixin.intVal < 0 or
       isMixin.intVal > high(TSymChoiceRule).int:
-    localError(n.sons[2].info, errConstExprExpected)
+    localError(c.config, n.sons[2].info, errConstExprExpected)
     return errorNode(c, n)
 
   let id = newIdentNode(getIdent(sl.strVal), n.info)
@@ -225,9 +225,9 @@ proc semOf(c: PContext, n: PNode): PNode =
     let y = skipTypes(n.sons[2].typ, abstractPtrs-{tyTypeDesc})
 
     if x.kind == tyTypeDesc or y.kind != tyTypeDesc:
-      localError(n.info, errXExpectsObjectTypes, "of")
+      localError(c.config, n.info, "'of' takes object types")
     elif b.kind != tyObject or a.kind != tyObject:
-      localError(n.info, errXExpectsObjectTypes, "of")
+      localError(c.config, n.info, "'of' takes object types")
     else:
       let diff = inheritanceDiff(a, b)
       # | returns: 0 iff `a` == `b`
@@ -236,26 +236,26 @@ proc semOf(c: PContext, n: PNode): PNode =
       # | returns: `maxint` iff `a` and `b` are not compatible at all
       if diff <= 0:
         # optimize to true:
-        message(n.info, hintConditionAlwaysTrue, renderTree(n))
+        message(c.config, n.info, hintConditionAlwaysTrue, renderTree(n))
         result = newIntNode(nkIntLit, 1)
         result.info = n.info
-        result.typ = getSysType(tyBool)
+        result.typ = getSysType(c.graph, n.info, tyBool)
         return result
       elif diff == high(int):
-        localError(n.info, errXcanNeverBeOfThisSubtype, typeToString(a))
+        localError(c.config, n.info, "'$1' cannot be of this subtype" % typeToString(a))
   else:
-    localError(n.info, errXExpectsTwoArguments, "of")
-  n.typ = getSysType(tyBool)
+    localError(c.config, n.info, "'of' takes 2 arguments")
+  n.typ = getSysType(c.graph, n.info, tyBool)
   result = n
 
 proc magicsAfterOverloadResolution(c: PContext, n: PNode,
                                    flags: TExprFlags): PNode =
   case n[0].sym.magic
   of mAddr:
-    checkSonsLen(n, 2)
+    checkSonsLen(n, 2, c.config)
     result = semAddr(c, n.sons[1], n[0].sym.name.s == "unsafeAddr")
   of mTypeOf:
-    checkSonsLen(n, 2)
+    checkSonsLen(n, 2, c.config)
     result = semTypeOf(c, n.sons[1])
   of mArrGet: result = semArrGet(c, n, flags)
   of mArrPut: result = semArrPut(c, n, flags)
@@ -267,8 +267,8 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
   of mIsPartOf: result = semIsPartOf(c, n, flags)
   of mTypeTrait: result = semTypeTraits(c, n)
   of mAstToStr:
-    result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
-    result.typ = getSysType(tyString)
+    result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, c.graph)
+    result.typ = getSysType(c.graph, n.info, tyString)
   of mInstantiationInfo: result = semInstantiationInfo(c, n)
   of mOrd: result = semOrd(c, n)
   of mOf: result = semOf(c, n)
@@ -281,11 +281,11 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
   of mDotDot:
     result = n
   of mRoof:
-    localError(n.info, "builtin roof operator is not supported anymore")
+    localError(c.config, n.info, "builtin roof operator is not supported anymore")
   of mPlugin:
     let plugin = getPlugin(n[0].sym)
     if plugin.isNil:
-      localError(n.info, "cannot find plugin " & n[0].sym.name.s)
+      localError(c.config, n.info, "cannot find plugin " & n[0].sym.name.s)
       result = n
     else:
       result = plugin(c, n)
diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim
index cfa0fbd05..1e0802953 100644
--- a/compiler/semobjconstr.nim
+++ b/compiler/semobjconstr.nim
@@ -39,32 +39,32 @@ proc mergeInitStatus(existing: var InitStatus, newStatus: InitStatus) =
   of initUnknown:
     discard
 
-proc invalidObjConstr(n: PNode) =
+proc invalidObjConstr(c: PContext, n: PNode) =
   if n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s[0] == ':':
-    localError(n.info, "incorrect object construction syntax; use a space after the colon")
+    localError(c.config, n.info, "incorrect object construction syntax; use a space after the colon")
   else:
-    localError(n.info, "incorrect object construction syntax")
+    localError(c.config, n.info, "incorrect object construction syntax")
 
-proc locateFieldInInitExpr(field: PSym, initExpr: PNode): PNode =
+proc locateFieldInInitExpr(c: PContext, field: PSym, initExpr: PNode): PNode =
   # Returns the assignment nkExprColonExpr node or nil
   let fieldId = field.name.id
   for i in 1 ..< initExpr.len:
     let assignment = initExpr[i]
     if assignment.kind != nkExprColonExpr:
-      invalidObjConstr(assignment)
+      invalidObjConstr(c, assignment)
       continue
 
-    if fieldId == considerQuotedIdent(assignment[0]).id:
+    if fieldId == considerQuotedIdent(c.config, assignment[0]).id:
       return assignment
 
 proc semConstrField(c: PContext, flags: TExprFlags,
                     field: PSym, initExpr: PNode): PNode =
-  let assignment = locateFieldInInitExpr(field, initExpr)
+  let assignment = locateFieldInInitExpr(c, field, initExpr)
   if assignment != nil:
     if nfSem in assignment.flags: return assignment[1]
     if not fieldVisible(c, field):
-      localError(initExpr.info,
-        "the field '$1' is not accessible.", [field.name.s])
+      localError(c.config, initExpr.info,
+        "the field '$1' is not accessible." % [field.name.s])
       return
 
     var initValue = semExprFlagDispatched(c, assignment[1], flags)
@@ -101,25 +101,25 @@ iterator directFieldsInRecList(recList: PNode): PNode =
   if recList.kind == nkSym:
     yield recList
   else:
-    internalAssert recList.kind == nkRecList
+    doAssert recList.kind == nkRecList
     for field in recList:
       if field.kind != nkSym: continue
       yield field
 
 template quoteStr(s: string): string = "'" & s & "'"
 
-proc fieldsPresentInInitExpr(fieldsRecList, initExpr: PNode): string =
+proc fieldsPresentInInitExpr(c: PContext, fieldsRecList, initExpr: PNode): string =
   result = ""
   for field in directFieldsInRecList(fieldsRecList):
-    let assignment = locateFieldInInitExpr(field.sym, initExpr)
+    let assignment = locateFieldInInitExpr(c, field.sym, initExpr)
     if assignment != nil:
       if result.len != 0: result.add ", "
       result.add field.sym.name.s.quoteStr
 
-proc missingMandatoryFields(fieldsRecList, initExpr: PNode): string =
+proc missingMandatoryFields(c: PContext, fieldsRecList, initExpr: PNode): string =
   for r in directFieldsInRecList(fieldsRecList):
     if {tfNotNil, tfNeedsInit} * r.sym.typ.flags != {}:
-      let assignment = locateFieldInInitExpr(r.sym, initExpr)
+      let assignment = locateFieldInInitExpr(c, r.sym, initExpr)
       if assignment == nil:
         if result == nil:
           result = r.sym.name.s
@@ -127,10 +127,10 @@ proc missingMandatoryFields(fieldsRecList, initExpr: PNode): string =
           result.add ", "
           result.add r.sym.name.s
 
-proc checkForMissingFields(recList, initExpr: PNode) =
-  let missing = missingMandatoryFields(recList, initExpr)
+proc checkForMissingFields(c: PContext, recList, initExpr: PNode) =
+  let missing = missingMandatoryFields(c, recList, initExpr)
   if missing != nil:
-    localError(initExpr.info, "fields not initialized: $1.", [missing])
+    localError(c.config, initExpr.info, "fields not initialized: $1.", [missing])
 
 proc semConstructFields(c: PContext, recNode: PNode,
                         initExpr: PNode, flags: TExprFlags): InitStatus =
@@ -146,14 +146,14 @@ proc semConstructFields(c: PContext, recNode: PNode,
     template fieldsPresentInBranch(branchIdx: int): string =
       let branch = recNode[branchIdx]
       let fields = branch[branch.len - 1]
-      fieldsPresentInInitExpr(fields, initExpr)
+      fieldsPresentInInitExpr(c, fields, initExpr)
 
     template checkMissingFields(branchNode: PNode) =
       let fields = branchNode[branchNode.len - 1]
-      checkForMissingFields(fields, initExpr)
+      checkForMissingFields(c, fields, initExpr)
 
-    let discriminator = recNode.sons[0];
-    internalAssert discriminator.kind == nkSym
+    let discriminator = recNode.sons[0]
+    internalAssert c.config, discriminator.kind == nkSym
     var selectedBranch = -1
 
     for i in 1 ..< recNode.len:
@@ -164,9 +164,9 @@ proc semConstructFields(c: PContext, recNode: PNode,
         if selectedBranch != -1:
           let prevFields = fieldsPresentInBranch(selectedBranch)
           let currentFields = fieldsPresentInBranch(i)
-          localError(initExpr.info,
-            "The fields ($1) and ($2) cannot be initialized together, " &
-            "because they are from conflicting branches in the case object.",
+          localError(c.config, initExpr.info,
+            ("The fields '$1' and '$2' cannot be initialized together, " &
+            "because they are from conflicting branches in the case object.") %
             [prevFields, currentFields])
           result = initConflict
         else:
@@ -179,9 +179,9 @@ proc semConstructFields(c: PContext, recNode: PNode,
                                             discriminator.sym, initExpr)
       if discriminatorVal == nil:
         let fields = fieldsPresentInBranch(selectedBranch)
-        localError(initExpr.info,
-          "you must provide a compile-time value for the discriminator '$1' " &
-          "in order to prove that it's safe to initialize $2.",
+        localError(c.config, initExpr.info,
+          ("you must provide a compile-time value for the discriminator '$1' " &
+          "in order to prove that it's safe to initialize $2.") %
           [discriminator.sym.name.s, fields])
         mergeInitStatus(result, initNone)
       else:
@@ -189,7 +189,7 @@ proc semConstructFields(c: PContext, recNode: PNode,
 
         template wrongBranchError(i) =
           let fields = fieldsPresentInBranch(i)
-          localError(initExpr.info,
+          localError(c.config, initExpr.info,
             "a case selecting discriminator '$1' with value '$2' " &
             "appears in the object construction, but the field(s) $3 " &
             "are in conflict with this value.",
@@ -219,7 +219,7 @@ proc semConstructFields(c: PContext, recNode: PNode,
         # value was given to the discrimator. We can assume that it will be
         # initialized to zero and this will select a particular branch as
         # a result:
-        let matchedBranch = recNode.pickCaseBranch newIntLit(0)
+        let matchedBranch = recNode.pickCaseBranch newIntLit(c.graph, initExpr.info, 0)
         checkMissingFields matchedBranch
       else:
         result = initPartial
@@ -239,20 +239,17 @@ proc semConstructFields(c: PContext, recNode: PNode,
     result = if e != nil: initFull else: initNone
 
   else:
-    internalAssert false
+    internalAssert c.config, false
 
 proc semConstructType(c: PContext, initExpr: PNode,
                       t: PType, flags: TExprFlags): InitStatus =
   var t = t
   result = initUnknown
-
   while true:
     let status = semConstructFields(c, t.n, initExpr, flags)
     mergeInitStatus(result, status)
-
     if status in {initPartial, initNone, initUnknown}:
-      checkForMissingFields t.n, initExpr
-
+      checkForMissingFields c, t.n, initExpr
     let base = t.sons[0]
     if base == nil: break
     t = skipTypes(base, skipPtrs)
@@ -263,13 +260,13 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
   for child in n: result.add child
 
   if t == nil:
-    localError(n.info, errGenerated, "object constructor needs an object type")
+    localError(c.config, n.info, errGenerated, "object constructor needs an object type")
     return
 
   t = skipTypes(t, {tyGenericInst, tyAlias, tySink})
   if t.kind == tyRef: t = skipTypes(t.sons[0], {tyGenericInst, tyAlias, tySink})
   if t.kind != tyObject:
-    localError(n.info, errGenerated, "object constructor needs an object type")
+    localError(c.config, n.info, errGenerated, "object constructor needs an object type")
     return
 
   # Check if the object is fully initialized by recursively testing each
@@ -296,17 +293,16 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
     let field = result[i]
     if nfSem notin field.flags:
       if field.kind != nkExprColonExpr:
-        invalidObjConstr(field)
+        invalidObjConstr(c, field)
         continue
-      let id = considerQuotedIdent(field[0])
+      let id = considerQuotedIdent(c.config, field[0])
       # This node was not processed. There are two possible reasons:
       # 1) It was shadowed by a field with the same name on the left
       for j in 1 ..< i:
-        let prevId = considerQuotedIdent(result[j][0])
+        let prevId = considerQuotedIdent(c.config, result[j][0])
         if prevId.id == id.id:
-          localError(field.info, errFieldInitTwice, id.s)
+          localError(c.config, field.info, errFieldInitTwice % id.s)
           return
       # 2) No such field exists in the constructed type
-      localError(field.info, errUndeclaredFieldX, id.s)
+      localError(c.config, field.info, errUndeclaredFieldX % id.s)
       return
-
diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim
index e12fd84bb..ea5aab628 100644
--- a/compiler/semparallel.nim
+++ b/compiler/semparallel.nim
@@ -23,7 +23,8 @@
 
 import
   ast, astalgo, idents, lowerings, magicsys, guards, sempass2, msgs,
-  renderer, types
+  renderer, types, modulegraphs, options
+
 from trees import getMagic
 from strutils import `%`
 
@@ -73,12 +74,15 @@ type
                         # the 'parallel' section
     currentSpawnId: int
     inLoop: int
+    graph: ModuleGraph
 
-proc initAnalysisCtx(): AnalysisCtx =
+proc initAnalysisCtx(g: ModuleGraph): AnalysisCtx =
   result.locals = @[]
   result.slices = @[]
   result.args = @[]
-  result.guards = @[]
+  result.guards.s = @[]
+  result.guards.o = initOperators(g)
+  result.graph = g
 
 proc lookupSlot(c: AnalysisCtx; s: PSym): int =
   for i in 0..<c.locals.len:
@@ -117,7 +121,7 @@ proc checkLocal(c: AnalysisCtx; n: PNode) =
   if isLocal(n):
     let s = c.lookupSlot(n.sym)
     if s >= 0 and c.locals[s].stride != nil:
-      localError(n.info, "invalid usage of counter after increment")
+      localError(c.graph.config, n.info, "invalid usage of counter after increment")
   else:
     for i in 0 ..< n.safeLen: checkLocal(c, n.sons[i])
 
@@ -126,14 +130,14 @@ template `?`(x): untyped = x.renderTree
 proc checkLe(c: AnalysisCtx; a, b: PNode) =
   case proveLe(c.guards, a, b)
   of impUnknown:
-    localError(a.info, "cannot prove: " & ?a & " <= " & ?b & " (bounds check)")
+    localError(c.graph.config, a.info, "cannot prove: " & ?a & " <= " & ?b & " (bounds check)")
   of impYes: discard
   of impNo:
-    localError(a.info, "can prove: " & ?a & " > " & ?b & " (bounds check)")
+    localError(c.graph.config, a.info, "can prove: " & ?a & " > " & ?b & " (bounds check)")
 
 proc checkBounds(c: AnalysisCtx; arr, idx: PNode) =
   checkLe(c, arr.lowBound, idx)
-  checkLe(c, idx, arr.highBound)
+  checkLe(c, idx, arr.highBound(c.guards.o))
 
 proc addLowerBoundAsFacts(c: var AnalysisCtx) =
   for v in c.locals:
@@ -142,34 +146,34 @@ proc addLowerBoundAsFacts(c: var AnalysisCtx) =
 
 proc addSlice(c: var AnalysisCtx; n: PNode; x, le, ri: PNode) =
   checkLocal(c, n)
-  let le = le.canon
-  let ri = ri.canon
+  let le = le.canon(c.guards.o)
+  let ri = ri.canon(c.guards.o)
   # perform static bounds checking here; and not later!
-  let oldState = c.guards.len
+  let oldState = c.guards.s.len
   addLowerBoundAsFacts(c)
   c.checkBounds(x, le)
   c.checkBounds(x, ri)
-  c.guards.setLen(oldState)
+  c.guards.s.setLen(oldState)
   c.slices.add((x, le, ri, c.currentSpawnId, c.inLoop > 0))
 
-proc overlap(m: TModel; x,y,c,d: PNode) =
+proc overlap(m: TModel; conf: ConfigRef; x,y,c,d: PNode) =
   #  X..Y and C..D overlap iff (X <= D and C <= Y)
   case proveLe(m, c, y)
   of impUnknown:
     case proveLe(m, x, d)
     of impNo: discard
     of impUnknown, impYes:
-      localError(x.info,
+      localError(conf, x.info,
         "cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" %
             [?c, ?y, ?x, ?y, ?c, ?d])
   of impYes:
     case proveLe(m, x, d)
     of impUnknown:
-      localError(x.info,
+      localError(conf, x.info,
         "cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" %
           [?x, ?d, ?x, ?y, ?c, ?d])
     of impYes:
-      localError(x.info, "($#)..($#) not disjoint from ($#)..($#)" %
+      localError(conf, x.info, "($#)..($#) not disjoint from ($#)..($#)" %
                 [?c, ?y, ?x, ?y, ?c, ?d])
     of impNo: discard
   of impNo: discard
@@ -187,7 +191,7 @@ proc subStride(c: AnalysisCtx; n: PNode): PNode =
   if isLocal(n):
     let s = c.lookupSlot(n.sym)
     if s >= 0 and c.locals[s].stride != nil:
-      result = n +@ c.locals[s].stride.intVal
+      result = buildAdd(n, c.locals[s].stride.intVal, c.guards.o)
     else:
       result = n
   elif n.safeLen > 0:
@@ -203,7 +207,7 @@ proc checkSlicesAreDisjoint(c: var AnalysisCtx) =
   addLowerBoundAsFacts(c)
   # Every slice used in a loop needs to be disjoint with itself:
   for x,a,b,id,inLoop in items(c.slices):
-    if inLoop: overlap(c.guards, a,b, c.subStride(a), c.subStride(b))
+    if inLoop: overlap(c.guards, c.graph.config, a,b, c.subStride(a), c.subStride(b))
   # Another tricky example is:
   #   while true:
   #     spawn f(a[i])
@@ -231,21 +235,21 @@ proc checkSlicesAreDisjoint(c: var AnalysisCtx) =
           # XXX strictly speaking, 'or' is not correct here and it needs to
           # be 'and'. However this prevents too many obviously correct programs
           # like f(a[0..x]); for i in x+1 .. a.high: f(a[i])
-          overlap(c.guards, x.a, x.b, y.a, y.b)
+          overlap(c.guards, c.graph.config, x.a, x.b, y.a, y.b)
         elif (let k = simpleSlice(x.a, x.b); let m = simpleSlice(y.a, y.b);
               k >= 0 and m >= 0):
           # ah I cannot resist the temptation and add another sweet heuristic:
           # if both slices have the form (i+k)..(i+k)  and (i+m)..(i+m) we
           # check they are disjoint and k < stride and m < stride:
-          overlap(c.guards, x.a, x.b, y.a, y.b)
+          overlap(c.guards, c.graph.config, x.a, x.b, y.a, y.b)
           let stride = min(c.stride(x.a), c.stride(y.a))
           if k < stride and m < stride:
             discard
           else:
-            localError(x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" %
+            localError(c.graph.config, x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" %
               [?x.a, ?x.b, ?y.a, ?y.b])
         else:
-          localError(x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" %
+          localError(c.graph.config, x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" %
             [?x.a, ?x.b, ?y.a, ?y.b])
 
 proc analyse(c: var AnalysisCtx; n: PNode)
@@ -292,31 +296,31 @@ proc analyseCall(c: var AnalysisCtx; n: PNode; op: PSym) =
 
 proc analyseCase(c: var AnalysisCtx; n: PNode) =
   analyse(c, n.sons[0])
-  let oldFacts = c.guards.len
+  let oldFacts = c.guards.s.len
   for i in 1..<n.len:
     let branch = n.sons[i]
-    setLen(c.guards, oldFacts)
+    setLen(c.guards.s, oldFacts)
     addCaseBranchFacts(c.guards, n, i)
     for i in 0 ..< branch.len:
       analyse(c, branch.sons[i])
-  setLen(c.guards, oldFacts)
+  setLen(c.guards.s, oldFacts)
 
 proc analyseIf(c: var AnalysisCtx; n: PNode) =
   analyse(c, n.sons[0].sons[0])
-  let oldFacts = c.guards.len
-  addFact(c.guards, canon(n.sons[0].sons[0]))
+  let oldFacts = c.guards.s.len
+  addFact(c.guards, canon(n.sons[0].sons[0], c.guards.o))
 
   analyse(c, n.sons[0].sons[1])
   for i in 1..<n.len:
     let branch = n.sons[i]
-    setLen(c.guards, oldFacts)
+    setLen(c.guards.s, oldFacts)
     for j in 0..i-1:
-      addFactNeg(c.guards, canon(n.sons[j].sons[0]))
+      addFactNeg(c.guards, canon(n.sons[j].sons[0], c.guards.o))
     if branch.len > 1:
-      addFact(c.guards, canon(branch.sons[0]))
+      addFact(c.guards, canon(branch.sons[0], c.guards.o))
     for i in 0 ..< branch.len:
       analyse(c, branch.sons[i])
-  setLen(c.guards, oldFacts)
+  setLen(c.guards.s, oldFacts)
 
 proc analyse(c: var AnalysisCtx; n: PNode) =
   case n.kind
@@ -349,7 +353,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
       c.addSlice(n, n[0], n[1], n[1])
     analyseSons(c, n)
   of nkReturnStmt, nkRaiseStmt, nkTryStmt:
-    localError(n.info, "invalid control flow for 'parallel'")
+    localError(c.graph.config, n.info, "invalid control flow for 'parallel'")
     # 'break' that leaves the 'parallel' section is not valid either
     # or maybe we should generate a 'try' XXX
   of nkVarSection, nkLetSection:
@@ -365,7 +369,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
           if it[j].isLocal:
             let slot = c.getSlot(it[j].sym)
             if slot.lower.isNil: slot.lower = value
-            else: internalError(it.info, "slot already has a lower bound")
+            else: internalError(c.graph.config, it.info, "slot already has a lower bound")
         if not isSpawned: analyse(c, value)
   of nkCaseStmt: analyseCase(c, n)
   of nkWhen, nkIfStmt, nkIfExpr: analyseIf(c, n)
@@ -378,14 +382,14 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
     else:
       # loop may never execute:
       let oldState = c.locals.len
-      let oldFacts = c.guards.len
-      addFact(c.guards, canon(n.sons[0]))
+      let oldFacts = c.guards.s.len
+      addFact(c.guards, canon(n.sons[0], c.guards.o))
       analyse(c, n.sons[1])
       setLen(c.locals, oldState)
-      setLen(c.guards, oldFacts)
+      setLen(c.guards.s, oldFacts)
       # we know after the loop the negation holds:
       if not hasSubnodeWith(n.sons[1], nkBreakStmt):
-        addFactNeg(c.guards, canon(n.sons[0]))
+        addFactNeg(c.guards, canon(n.sons[0], c.guards.o))
     dec c.inLoop
   of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
       nkMacroDef, nkTemplateDef, nkConstSection, nkPragma, nkFuncDef:
@@ -393,13 +397,13 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
   else:
     analyseSons(c, n)
 
-proc transformSlices(n: PNode): PNode =
+proc transformSlices(g: ModuleGraph; n: PNode): PNode =
   if n.kind in nkCallKinds and n[0].kind == nkSym:
     let op = n[0].sym
     if op.name.s == "[]" and op.fromSystem:
       result = copyNode(n)
-      let opSlice = newSymNode(createMagic("slice", mSlice))
-      opSlice.typ = getSysType(tyInt)
+      let opSlice = newSymNode(createMagic(g, "slice", mSlice))
+      opSlice.typ = getSysType(g, n.info, tyInt)
       result.add opSlice
       result.add n[1]
       let slice = n[2].skipStmtList
@@ -409,49 +413,49 @@ proc transformSlices(n: PNode): PNode =
   if n.safeLen > 0:
     result = shallowCopy(n)
     for i in 0 ..< n.len:
-      result.sons[i] = transformSlices(n.sons[i])
+      result.sons[i] = transformSlices(g, n.sons[i])
   else:
     result = n
 
-proc transformSpawn(owner: PSym; n, barrier: PNode): PNode
-proc transformSpawnSons(owner: PSym; n, barrier: PNode): PNode =
+proc transformSpawn(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode
+proc transformSpawnSons(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode =
   result = shallowCopy(n)
   for i in 0 ..< n.len:
-    result.sons[i] = transformSpawn(owner, n.sons[i], barrier)
+    result.sons[i] = transformSpawn(g, owner, n.sons[i], barrier)
 
-proc transformSpawn(owner: PSym; n, barrier: PNode): PNode =
+proc transformSpawn(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode =
   case n.kind
   of nkVarSection, nkLetSection:
     result = nil
     for it in n:
       let b = it.lastSon
       if getMagic(b) == mSpawn:
-        if it.len != 3: localError(it.info, "invalid context for 'spawn'")
-        let m = transformSlices(b)
+        if it.len != 3: localError(g.config, it.info, "invalid context for 'spawn'")
+        let m = transformSlices(g, b)
         if result.isNil:
           result = newNodeI(nkStmtList, n.info)
           result.add n
         let t = b[1][0].typ.sons[0]
         if spawnResult(t, true) == srByVar:
-          result.add wrapProcForSpawn(owner, m, b.typ, barrier, it[0])
+          result.add wrapProcForSpawn(g, owner, m, b.typ, barrier, it[0])
           it.sons[it.len-1] = emptyNode
         else:
-          it.sons[it.len-1] = wrapProcForSpawn(owner, m, b.typ, barrier, nil)
+          it.sons[it.len-1] = wrapProcForSpawn(g, owner, m, b.typ, barrier, nil)
     if result.isNil: result = n
   of nkAsgn, nkFastAsgn:
     let b = n[1]
     if getMagic(b) == mSpawn and (let t = b[1][0].typ.sons[0];
         spawnResult(t, true) == srByVar):
-      let m = transformSlices(b)
-      return wrapProcForSpawn(owner, m, b.typ, barrier, n[0])
-    result = transformSpawnSons(owner, n, barrier)
+      let m = transformSlices(g, b)
+      return wrapProcForSpawn(g, owner, m, b.typ, barrier, n[0])
+    result = transformSpawnSons(g, owner, n, barrier)
   of nkCallKinds:
     if getMagic(n) == mSpawn:
-      result = transformSlices(n)
-      return wrapProcForSpawn(owner, result, n.typ, barrier, nil)
-    result = transformSpawnSons(owner, n, barrier)
+      result = transformSlices(g, n)
+      return wrapProcForSpawn(g, owner, result, n.typ, barrier, nil)
+    result = transformSpawnSons(g, owner, n, barrier)
   elif n.safeLen > 0:
-    result = transformSpawnSons(owner, n, barrier)
+    result = transformSpawnSons(g, owner, n, barrier)
   else:
     result = n
 
@@ -461,7 +465,7 @@ proc checkArgs(a: var AnalysisCtx; n: PNode) =
 proc generateAliasChecks(a: AnalysisCtx; result: PNode) =
   discard "too implement"
 
-proc liftParallel*(owner: PSym; n: PNode): PNode =
+proc liftParallel*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
   # this needs to be called after the 'for' loop elimination
 
   # first pass:
@@ -470,17 +474,17 @@ proc liftParallel*(owner: PSym; n: PNode): PNode =
   # - detect used arguments
   #echo "PAR ", renderTree(n)
 
-  var a = initAnalysisCtx()
+  var a = initAnalysisCtx(g)
   let body = n.lastSon
   analyse(a, body)
   if a.spawns == 0:
-    localError(n.info, "'parallel' section without 'spawn'")
+    localError(g.config, n.info, "'parallel' section without 'spawn'")
   checkSlicesAreDisjoint(a)
   checkArgs(a, body)
 
   var varSection = newNodeI(nkVarSection, n.info)
   var temp = newSym(skTemp, getIdent"barrier", owner, n.info)
-  temp.typ = magicsys.getCompilerProc("Barrier").typ
+  temp.typ = magicsys.getCompilerProc(g, "Barrier").typ
   incl(temp.flags, sfFromGeneric)
   let tempNode = newSymNode(temp)
   varSection.addVar tempNode
@@ -489,6 +493,6 @@ proc liftParallel*(owner: PSym; n: PNode): PNode =
   result = newNodeI(nkStmtList, n.info)
   generateAliasChecks(a, result)
   result.add varSection
-  result.add callCodegenProc("openBarrier", barrier)
-  result.add transformSpawn(owner, body, barrier)
-  result.add callCodegenProc("closeBarrier", barrier)
+  result.add callCodegenProc(g, "openBarrier", barrier)
+  result.add transformSpawn(g, owner, body, barrier)
+  result.add callCodegenProc(g, "closeBarrier", barrier)
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index d2a10f714..b66d7d9f2 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -9,7 +9,8 @@
 
 import
   intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
-  wordrecg, strutils, options, guards, writetracking
+  wordrecg, strutils, options, guards, writetracking, configuration,
+  modulegraphs
 
 when defined(useDfa):
   import dfa
@@ -52,6 +53,8 @@ type
     locked: seq[PNode] # locked locations
     gcUnsafe, isRecursive, isToplevel, hasSideEffect, inEnforcedGcSafe: bool
     maxLockLevel, currLockLevel: TLockLevel
+    config: ConfigRef
+    graph: ModuleGraph
   PEffects = var TEffects
 
 proc `<`(a, b: TLockLevel): bool {.borrow.}
@@ -72,24 +75,23 @@ proc getLockLevel(t: PType): TLockLevel =
 
 proc lockLocations(a: PEffects; pragma: PNode) =
   if pragma.kind != nkExprColonExpr:
-    localError(pragma.info, errGenerated, "locks pragma without argument")
+    localError(a.config, pragma.info, "locks pragma without argument")
     return
   var firstLL = TLockLevel(-1'i16)
   for x in pragma[1]:
     let thisLL = getLockLevel(x.typ)
     if thisLL != 0.TLockLevel:
       if thisLL < 0.TLockLevel or thisLL > MaxLockLevel.TLockLevel:
-        localError(x.info, "invalid lock level: " & $thisLL)
+        localError(a.config, x.info, "invalid lock level: " & $thisLL)
       elif firstLL < 0.TLockLevel: firstLL = thisLL
       elif firstLL != thisLL:
-        localError(x.info, errGenerated,
+        localError(a.config, x.info,
           "multi-lock requires the same static lock level for every operand")
       a.maxLockLevel = max(a.maxLockLevel, firstLL)
     a.locked.add x
   if firstLL >= 0.TLockLevel and firstLL != a.currLockLevel:
     if a.currLockLevel > 0.TLockLevel and a.currLockLevel <= firstLL:
-      localError(pragma.info, errGenerated,
-        "invalid nested locking")
+      localError(a.config, pragma.info, "invalid nested locking")
     a.currLockLevel = firstLL
 
 proc guardGlobal(a: PEffects; n: PNode; guard: PSym) =
@@ -102,7 +104,7 @@ proc guardGlobal(a: PEffects; n: PNode; guard: PSym) =
   #  message(n.info, warnUnguardedAccess, renderTree(n))
   #else:
   if not a.isTopLevel:
-    localError(n.info, errGenerated, "unguarded access: " & renderTree(n))
+    localError(a.config, n.info, "unguarded access: " & renderTree(n))
 
 # 'guard*' are checks which are concerned with 'guard' annotations
 # (var x{.guard: y.}: int)
@@ -125,7 +127,7 @@ proc guardDotAccess(a: PEffects; n: PNode) =
         if ty == nil: break
         ty = ty.skipTypes(skipPtrs)
     if field == nil:
-      localError(n.info, errGenerated, "invalid guard field: " & g.name.s)
+      localError(a.config, n.info, "invalid guard field: " & g.name.s)
       return
     g = field
     #ri.sym.guard = field
@@ -138,13 +140,13 @@ proc guardDotAccess(a: PEffects; n: PNode) =
     for L in a.locked:
       #if a.guards.sameSubexprs(dot, L): return
       if guards.sameTree(dot, L): return
-    localError(n.info, errGenerated, "unguarded access: " & renderTree(n))
+    localError(a.config, n.info, "unguarded access: " & renderTree(n))
   else:
     guardGlobal(a, n, g)
 
 proc makeVolatile(a: PEffects; s: PSym) {.inline.} =
   template compileToCpp(a): untyped =
-    gCmd == cmdCompileToCpp or sfCompileToCpp in getModule(a.owner).flags
+    a.config.cmd == cmdCompileToCpp or sfCompileToCpp in getModule(a.owner).flags
   if a.inTryStmt > 0 and not compileToCpp(a):
     incl(s.flags, sfVolatile)
 
@@ -167,9 +169,9 @@ proc initVarViaNew(a: PEffects, n: PNode) =
   elif isLocalVar(a, s):
     makeVolatile(a, s)
 
-proc warnAboutGcUnsafe(n: PNode) =
+proc warnAboutGcUnsafe(n: PNode; conf: ConfigRef) =
   #assert false
-  message(n.info, warnGcUnsafe, renderTree(n))
+  message(conf, n.info, warnGcUnsafe, renderTree(n))
 
 proc markGcUnsafe(a: PEffects; reason: PSym) =
   if not a.inEnforcedGcSafe:
@@ -184,7 +186,7 @@ proc markGcUnsafe(a: PEffects; reason: PNode) =
         a.owner.gcUnsafetyReason = reason.sym
       else:
         a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent("<unknown>"),
-                                          a.owner, reason.info)
+                                          a.owner, reason.info, {})
 
 when true:
   template markSideEffect(a: PEffects; reason: typed) =
@@ -194,42 +196,42 @@ else:
     a.hasSideEffect = true
     markGcUnsafe(a, reason)
 
-proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet) =
+proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet; conf: ConfigRef) =
   let u = s.gcUnsafetyReason
   if u != nil and not cycleCheck.containsOrIncl(u.id):
     let msgKind = if onlyWarning: warnGcUnsafe2 else: errGenerated
     case u.kind
     of skLet, skVar:
-      message(s.info, msgKind,
+      message(conf, s.info, msgKind,
         ("'$#' is not GC-safe as it accesses '$#'" &
         " which is a global using GC'ed memory") % [s.name.s, u.name.s])
     of routineKinds:
       # recursive call *always* produces only a warning so the full error
       # message is printed:
-      listGcUnsafety(u, true, cycleCheck)
-      message(s.info, msgKind,
+      listGcUnsafety(u, true, cycleCheck, conf)
+      message(conf, s.info, msgKind,
         "'$#' is not GC-safe as it calls '$#'" %
         [s.name.s, u.name.s])
     of skParam, skForVar:
-      message(s.info, msgKind,
+      message(conf, s.info, msgKind,
         "'$#' is not GC-safe as it performs an indirect call via '$#'" %
         [s.name.s, u.name.s])
     else:
-      message(u.info, msgKind,
+      message(conf, u.info, msgKind,
         "'$#' is not GC-safe as it performs an indirect call here" % s.name.s)
 
-proc listGcUnsafety(s: PSym; onlyWarning: bool) =
+proc listGcUnsafety(s: PSym; onlyWarning: bool; conf: ConfigRef) =
   var cycleCheck = initIntSet()
-  listGcUnsafety(s, onlyWarning, cycleCheck)
+  listGcUnsafety(s, onlyWarning, cycleCheck, conf)
 
 proc useVar(a: PEffects, n: PNode) =
   let s = n.sym
   if isLocalVar(a, s):
     if s.id notin a.init:
       if {tfNeedsInit, tfNotNil} * s.typ.flags != {}:
-        message(n.info, warnProveInit, s.name.s)
+        message(a.config, n.info, warnProveInit, s.name.s)
       else:
-        message(n.info, warnUninit, s.name.s)
+        message(a.config, n.info, warnUninit, s.name.s)
       # prevent superfluous warnings about the same variable:
       a.init.add s.id
   if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet} and
@@ -257,34 +259,30 @@ proc addToIntersection(inter: var TIntersection, s: int) =
 proc throws(tracked, n: PNode) =
   if n.typ == nil or n.typ.kind != tyError: tracked.add n
 
-proc getEbase(): PType =
-  result = if getCompilerProc("Exception") != nil: sysTypeFromName"Exception"
-           else: sysTypeFromName"E_Base"
+proc getEbase(g: ModuleGraph; info: TLineInfo): PType =
+  result = g.sysTypeFromName(info, "Exception")
 
-proc excType(n: PNode): PType =
+proc excType(g: ModuleGraph; n: PNode): PType =
   # reraise is like raising E_Base:
-  let t = if n.kind == nkEmpty or n.typ.isNil: getEbase() else: n.typ
+  let t = if n.kind == nkEmpty or n.typ.isNil: getEbase(g, n.info) else: n.typ
   result = skipTypes(t, skipPtrs)
 
-proc createRaise(n: PNode): PNode =
+proc createRaise(g: ModuleGraph; n: PNode): PNode =
   result = newNode(nkType)
-  result.typ = getEbase()
+  result.typ = getEbase(g, n.info)
   if not n.isNil: result.info = n.info
 
-proc createTag(n: PNode): PNode =
+proc createTag(g: ModuleGraph; n: PNode): PNode =
   result = newNode(nkType)
-  if getCompilerProc("RootEffect") != nil:
-    result.typ = sysTypeFromName"RootEffect"
-  else:
-    result.typ = sysTypeFromName"TEffect"
+  result.typ = g.sysTypeFromName(n.info, "RootEffect")
   if not n.isNil: result.info = n.info
 
 proc addEffect(a: PEffects, e: PNode, useLineInfo=true) =
   assert e.kind != nkRaiseStmt
   var aa = a.exc
   for i in a.bottom ..< aa.len:
-    if sameType(aa[i].excType, e.excType):
-      if not useLineInfo or gCmd == cmdDoc: return
+    if sameType(a.graph.excType(aa[i]), a.graph.excType(e)):
+      if not useLineInfo or a.config.cmd == cmdDoc: return
       elif aa[i].info == e.info: return
   throws(a.exc, e)
 
@@ -292,25 +290,25 @@ proc addTag(a: PEffects, e: PNode, useLineInfo=true) =
   var aa = a.tags
   for i in 0 ..< aa.len:
     if sameType(aa[i].typ.skipTypes(skipPtrs), e.typ.skipTypes(skipPtrs)):
-      if not useLineInfo or gCmd == cmdDoc: return
+      if not useLineInfo or a.config.cmd == cmdDoc: return
       elif aa[i].info == e.info: return
   throws(a.tags, e)
 
 proc mergeEffects(a: PEffects, b, comesFrom: PNode) =
   if b.isNil:
-    addEffect(a, createRaise(comesFrom))
+    addEffect(a, createRaise(a.graph, comesFrom))
   else:
     for effect in items(b): addEffect(a, effect, useLineInfo=comesFrom != nil)
 
 proc mergeTags(a: PEffects, b, comesFrom: PNode) =
   if b.isNil:
-    addTag(a, createTag(comesFrom))
+    addTag(a, createTag(a.graph, comesFrom))
   else:
     for effect in items(b): addTag(a, effect, useLineInfo=comesFrom != nil)
 
 proc listEffects(a: PEffects) =
-  for e in items(a.exc):  message(e.info, hintUser, typeToString(e.typ))
-  for e in items(a.tags): message(e.info, hintUser, typeToString(e.typ))
+  for e in items(a.exc):  message(a.config, e.info, hintUser, typeToString(e.typ))
+  for e in items(a.tags): message(a.config, e.info, hintUser, typeToString(e.typ))
   #if a.maxLockLevel != 0:
   #  message(e.info, hintUser, "lockLevel: " & a.maxLockLevel)
 
@@ -320,7 +318,7 @@ proc catches(tracked: PEffects, e: PType) =
   var i = tracked.bottom
   while i < L:
     # r supertype of e?
-    if safeInheritanceDiff(tracked.exc[i].excType, e) <= 0:
+    if safeInheritanceDiff(tracked.graph.excType(tracked.exc[i]), e) <= 0:
       tracked.exc.sons[i] = tracked.exc.sons[L-1]
       dec L
     else:
@@ -489,7 +487,7 @@ proc mergeLockLevels(tracked: PEffects, n: PNode, lockLevel: TLockLevel) =
   if lockLevel >= tracked.currLockLevel:
     # if in lock section:
     if tracked.currLockLevel > 0.TLockLevel:
-      localError n.info, errGenerated,
+      localError tracked.config, n.info, errGenerated,
         "expected lock level < " & $tracked.currLockLevel &
         " but got lock level " & $lockLevel
     tracked.maxLockLevel = max(tracked.maxLockLevel, lockLevel)
@@ -503,22 +501,22 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
   mergeTags(tracked, tagSpec, n)
 
   if notGcSafe(s.typ) and sfImportc notin s.flags:
-    if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
+    if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
     markGcUnsafe(tracked, s)
   if tfNoSideEffect notin s.typ.flags:
     markSideEffect(tracked, s)
   mergeLockLevels(tracked, n, s.getLockLevel)
 
-proc procVarcheck(n: PNode) =
+proc procVarcheck(n: PNode; conf: ConfigRef) =
   if n.kind in nkSymChoices:
-    for x in n: procVarCheck(x)
+    for x in n: procVarCheck(x, conf)
   elif n.kind == nkSym and n.sym.magic != mNone and n.sym.kind in routineKinds:
-    localError(n.info, errXCannotBePassedToProcVar, n.sym.name.s)
+    localError(conf, n.info, "'$1' cannot be passed to a procvar" % n.sym.name.s)
 
 proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
   let n = n.skipConv
   if paramType.isNil or paramType.kind != tyTypeDesc:
-    procVarcheck skipConvAndClosure(n)
+    procVarcheck skipConvAndClosure(n), tracked.config
   #elif n.kind in nkSymChoices:
   #  echo "came here"
   let paramType = paramType.skipTypesOrNil(abstractInst)
@@ -534,15 +532,16 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
       return
     case impliesNotNil(tracked.guards, n)
     of impUnknown:
-      message(n.info, errGenerated,
+      message(tracked.config, n.info, errGenerated,
               "cannot prove '$1' is not nil" % n.renderTree)
     of impNo:
-      message(n.info, errGenerated, "'$1' is provably nil" % n.renderTree)
+      message(tracked.config, n.info, errGenerated,
+              "'$1' is provably nil" % n.renderTree)
     of impYes: discard
 
 proc assumeTheWorst(tracked: PEffects; n: PNode; op: PType) =
-  addEffect(tracked, createRaise(n))
-  addTag(tracked, createTag(n))
+  addEffect(tracked, createRaise(tracked.graph, n))
+  addTag(tracked, createTag(tracked.graph, n))
   let lockLevel = if op.lockLevel == UnspecifiedLockLevel: UnknownLockLevel
                   else: op.lockLevel
   #if lockLevel == UnknownLockLevel:
@@ -557,7 +556,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
   let a = skipConvAndClosure(n)
   let op = a.typ
   if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit:
-    internalAssert op.n.sons[0].kind == nkEffectList
+    internalAssert tracked.config, op.n.sons[0].kind == nkEffectList
     var effectList = op.n.sons[0]
     let s = n.skipConv
     if s.kind == nkSym and s.sym.kind in routineKinds:
@@ -572,7 +571,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
         assumeTheWorst(tracked, n, op)
       # assume GcUnsafe unless in its type; 'forward' does not matter:
       if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
-        if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
+        if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
         markGcUnsafe(tracked, a)
       elif tfNoSideEffect notin op.flags and not isOwnedProcVar(a, tracked.owner):
         markSideEffect(tracked, a)
@@ -580,7 +579,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
       mergeEffects(tracked, effectList.sons[exceptionEffects], n)
       mergeTags(tracked, effectList.sons[tagEffects], n)
       if notGcSafe(op):
-        if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
+        if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
         markGcUnsafe(tracked, a)
       elif tfNoSideEffect notin op.flags:
         markSideEffect(tracked, a)
@@ -592,7 +591,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
     # XXX figure out why this can be a non tyProc here. See httpclient.nim for an
     # example that triggers it.
     if argtype.kind == tyProc and notGcSafe(argtype) and not tracked.inEnforcedGcSafe:
-      localError(n.info, $n & " is not GC safe")
+      localError(tracked.config, n.info, $n & " is not GC safe")
   notNilCheck(tracked, n, paramType)
 
 proc breaksBlock(n: PNode): bool =
@@ -608,18 +607,18 @@ proc breaksBlock(n: PNode): bool =
 proc trackCase(tracked: PEffects, n: PNode) =
   track(tracked, n.sons[0])
   let oldState = tracked.init.len
-  let oldFacts = tracked.guards.len
+  let oldFacts = tracked.guards.s.len
   let stringCase = skipTypes(n.sons[0].typ,
         abstractVarRange-{tyTypeDesc}).kind in {tyFloat..tyFloat128, tyString}
   let interesting = not stringCase and interestingCaseExpr(n.sons[0]) and
-        warnProveField in gNotes
+        warnProveField in tracked.config.notes
   var inter: TIntersection = @[]
   var toCover = 0
   for i in 1..<n.len:
     let branch = n.sons[i]
     setLen(tracked.init, oldState)
     if interesting:
-      setLen(tracked.guards, oldFacts)
+      setLen(tracked.guards.s, oldFacts)
       addCaseBranchFacts(tracked.guards, n, i)
     for i in 0 ..< branch.len:
       track(tracked, branch.sons[i])
@@ -632,11 +631,11 @@ proc trackCase(tracked: PEffects, n: PNode) =
     for id, count in items(inter):
       if count >= toCover: tracked.init.add id
     # else we can't merge
-  setLen(tracked.guards, oldFacts)
+  setLen(tracked.guards.s, oldFacts)
 
 proc trackIf(tracked: PEffects, n: PNode) =
   track(tracked, n.sons[0].sons[0])
-  let oldFacts = tracked.guards.len
+  let oldFacts = tracked.guards.s.len
   addFact(tracked.guards, n.sons[0].sons[0])
   let oldState = tracked.init.len
 
@@ -649,7 +648,7 @@ proc trackIf(tracked: PEffects, n: PNode) =
 
   for i in 1..<n.len:
     let branch = n.sons[i]
-    setLen(tracked.guards, oldFacts)
+    setLen(tracked.guards.s, oldFacts)
     for j in 0..i-1:
       addFactNeg(tracked.guards, n.sons[j].sons[0])
     if branch.len > 1:
@@ -665,7 +664,7 @@ proc trackIf(tracked: PEffects, n: PNode) =
     for id, count in items(inter):
       if count >= toCover: tracked.init.add id
     # else we can't merge as it is not exhaustive
-  setLen(tracked.guards, oldFacts)
+  setLen(tracked.guards.s, oldFacts)
 
 proc trackBlock(tracked: PEffects, n: PNode) =
   if n.kind in {nkStmtList, nkStmtListExpr}:
@@ -693,7 +692,7 @@ proc paramType(op: PType, i: int): PType =
 proc cstringCheck(tracked: PEffects; n: PNode) =
   if n.sons[0].typ.kind == tyCString and (let a = skipConv(n[1]);
       a.typ.kind == tyString and a.kind notin {nkStrLit..nkTripleStrLit}):
-    message(n.info, warnUnsafeCode, renderTree(n))
+    message(tracked.config, n.info, warnUnsafeCode, renderTree(n))
 
 proc track(tracked: PEffects, n: PNode) =
   case n.kind
@@ -735,7 +734,7 @@ proc track(tracked: PEffects, n: PNode) =
         if notGcSafe(op) and not importedFromC(a):
           # and it's not a recursive call:
           if not (a.kind == nkSym and a.sym == tracked.owner):
-            if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
+            if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
             markGcUnsafe(tracked, a)
         if tfNoSideEffect notin op.flags and not importedFromC(a):
           # and it's not a recursive call:
@@ -753,7 +752,7 @@ proc track(tracked: PEffects, n: PNode) =
           # var s: seq[notnil];  newSeq(s, 0)  is a special case!
           discard
         else:
-          message(arg.info, warnProveInit, $arg)
+          message(tracked.config, arg.info, warnProveInit, $arg)
     for i in 0 ..< safeLen(n):
       track(tracked, n.sons[i])
   of nkDotExpr:
@@ -761,7 +760,8 @@ proc track(tracked: PEffects, n: PNode) =
     for i in 0 ..< len(n): track(tracked, n.sons[i])
   of nkCheckedFieldExpr:
     track(tracked, n.sons[0])
-    if warnProveField in gNotes: checkFieldAccess(tracked.guards, n)
+    if warnProveField in tracked.config.notes:
+      checkFieldAccess(tracked.guards, n, tracked.config)
   of nkTryStmt: trackTryStmt(tracked, n)
   of nkPragma: trackPragmaStmt(tracked, n)
   of nkAsgn, nkFastAsgn:
@@ -798,11 +798,11 @@ proc track(tracked: PEffects, n: PNode) =
     else:
       # loop may never execute:
       let oldState = tracked.init.len
-      let oldFacts = tracked.guards.len
+      let oldFacts = tracked.guards.s.len
       addFact(tracked.guards, n.sons[0])
       track(tracked, n.sons[1])
       setLen(tracked.init, oldState)
-      setLen(tracked.guards, oldFacts)
+      setLen(tracked.guards.s, oldFacts)
   of nkForStmt, nkParForStmt:
     # we are very conservative here and assume the loop is never executed:
     let oldState = tracked.init.len
@@ -811,13 +811,13 @@ proc track(tracked: PEffects, n: PNode) =
     setLen(tracked.init, oldState)
   of nkObjConstr:
     when false: track(tracked, n.sons[0])
-    let oldFacts = tracked.guards.len
+    let oldFacts = tracked.guards.s.len
     for i in 1 ..< len(n):
       let x = n.sons[i]
       track(tracked, x)
       if x.sons[0].kind == nkSym and sfDiscriminant in x.sons[0].sym.flags:
         addDiscriminantFact(tracked.guards, x)
-    setLen(tracked.guards, oldFacts)
+    setLen(tracked.guards.s, oldFacts)
   of nkPragmaBlock:
     let pragmaList = n.sons[0]
     let oldLocked = tracked.locked.len
@@ -844,31 +844,31 @@ proc track(tracked: PEffects, n: PNode) =
   else:
     for i in 0 ..< safeLen(n): track(tracked, n.sons[i])
 
-proc subtypeRelation(spec, real: PNode): bool =
-  result = safeInheritanceDiff(real.excType, spec.typ) <= 0
+proc subtypeRelation(g: ModuleGraph; spec, real: PNode): bool =
+  result = safeInheritanceDiff(g.excType(real), spec.typ) <= 0
 
-proc checkRaisesSpec(spec, real: PNode, msg: string, hints: bool;
-                     effectPredicate: proc (a, b: PNode): bool {.nimcall.}) =
+proc checkRaisesSpec(g: ModuleGraph; spec, real: PNode, msg: string, hints: bool;
+                     effectPredicate: proc (g: ModuleGraph; a, b: PNode): bool {.nimcall.}) =
   # check that any real exception is listed in 'spec'; mark those as used;
   # report any unused exception
   var used = initIntSet()
   for r in items(real):
     block search:
       for s in 0 ..< spec.len:
-        if effectPredicate(spec[s], r):
+        if effectPredicate(g, spec[s], r):
           used.incl(s)
           break search
       # XXX call graph analysis would be nice here!
       pushInfoContext(spec.info)
-      localError(r.info, errGenerated, msg & typeToString(r.typ))
+      localError(g.config, r.info, errGenerated, msg & typeToString(r.typ))
       popInfoContext()
   # hint about unnecessarily listed exception types:
   if hints:
     for s in 0 ..< spec.len:
       if not used.contains(s):
-        message(spec[s].info, hintXDeclaredButNotUsed, renderTree(spec[s]))
+        message(g.config, spec[s].info, hintXDeclaredButNotUsed, renderTree(spec[s]))
 
-proc checkMethodEffects*(disp, branch: PSym) =
+proc checkMethodEffects*(g: ModuleGraph; disp, branch: PSym) =
   ## checks for consistent effects for multi methods.
   let actual = branch.typ.n.sons[0]
   if actual.len != effectListLen: return
@@ -876,42 +876,42 @@ proc checkMethodEffects*(disp, branch: PSym) =
   let p = disp.ast.sons[pragmasPos]
   let raisesSpec = effectSpec(p, wRaises)
   if not isNil(raisesSpec):
-    checkRaisesSpec(raisesSpec, actual.sons[exceptionEffects],
+    checkRaisesSpec(g, raisesSpec, actual.sons[exceptionEffects],
       "can raise an unlisted exception: ", hints=off, subtypeRelation)
   let tagsSpec = effectSpec(p, wTags)
   if not isNil(tagsSpec):
-    checkRaisesSpec(tagsSpec, actual.sons[tagEffects],
+    checkRaisesSpec(g, tagsSpec, actual.sons[tagEffects],
       "can have an unlisted effect: ", hints=off, subtypeRelation)
   if sfThread in disp.flags and notGcSafe(branch.typ):
-    localError(branch.info, "base method is GC-safe, but '$1' is not" %
+    localError(g.config, branch.info, "base method is GC-safe, but '$1' is not" %
                                 branch.name.s)
   if branch.typ.lockLevel > disp.typ.lockLevel:
     when true:
-      message(branch.info, warnLockLevel,
+      message(g.config, branch.info, warnLockLevel,
         "base method has lock level $1, but dispatcher has $2" %
           [$branch.typ.lockLevel, $disp.typ.lockLevel])
     else:
       # XXX make this an error after bigbreak has been released:
-      localError(branch.info,
+      localError(g.config, branch.info,
         "base method has lock level $1, but dispatcher has $2" %
           [$branch.typ.lockLevel, $disp.typ.lockLevel])
 
-proc setEffectsForProcType*(t: PType, n: PNode) =
+proc setEffectsForProcType*(g: ModuleGraph; t: PType, n: PNode) =
   var effects = t.n.sons[0]
-  internalAssert t.kind == tyProc and effects.kind == nkEffectList
+  if t.kind != tyProc or effects.kind != nkEffectList: return
 
   let
     raisesSpec = effectSpec(n, wRaises)
     tagsSpec = effectSpec(n, wTags)
   if not isNil(raisesSpec) or not isNil(tagsSpec):
-    internalAssert effects.len == 0
+    internalAssert g.config, effects.len == 0
     newSeq(effects.sons, effectListLen)
     if not isNil(raisesSpec):
       effects.sons[exceptionEffects] = raisesSpec
     if not isNil(tagsSpec):
       effects.sons[tagEffects] = tagsSpec
 
-proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
+proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; t: var TEffects) =
   newSeq(effects.sons, effectListLen)
   effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info)
   effects.sons[tagEffects] = newNodeI(nkArgList, s.info)
@@ -922,52 +922,55 @@ proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
   t.tags = effects.sons[tagEffects]
   t.owner = s
   t.init = @[]
-  t.guards = @[]
+  t.guards.s = @[]
+  t.guards.o = initOperators(g)
   t.locked = @[]
+  t.graph = g
+  t.config = g.config
 
-proc trackProc*(s: PSym, body: PNode) =
+proc trackProc*(g: ModuleGraph; s: PSym, body: PNode) =
   var effects = s.typ.n.sons[0]
-  internalAssert effects.kind == nkEffectList
+  if effects.kind != nkEffectList: return
   # effects already computed?
   if sfForward in s.flags: return
   if effects.len == effectListLen: return
 
   var t: TEffects
-  initEffects(effects, s, t)
+  initEffects(g, effects, s, t)
   track(t, body)
   if not isEmptyType(s.typ.sons[0]) and
       {tfNeedsInit, tfNotNil} * s.typ.sons[0].flags != {} and
       s.kind in {skProc, skFunc, skConverter, skMethod}:
     var res = s.ast.sons[resultPos].sym # get result symbol
     if res.id notin t.init:
-      message(body.info, warnProveInit, "result")
+      message(g.config, body.info, warnProveInit, "result")
   let p = s.ast.sons[pragmasPos]
   let raisesSpec = effectSpec(p, wRaises)
   if not isNil(raisesSpec):
-    checkRaisesSpec(raisesSpec, t.exc, "can raise an unlisted exception: ",
+    checkRaisesSpec(g, raisesSpec, t.exc, "can raise an unlisted exception: ",
                     hints=on, subtypeRelation)
     # after the check, use the formal spec:
     effects.sons[exceptionEffects] = raisesSpec
 
   let tagsSpec = effectSpec(p, wTags)
   if not isNil(tagsSpec):
-    checkRaisesSpec(tagsSpec, t.tags, "can have an unlisted effect: ",
+    checkRaisesSpec(g, tagsSpec, t.tags, "can have an unlisted effect: ",
                     hints=off, subtypeRelation)
     # after the check, use the formal spec:
     effects.sons[tagEffects] = tagsSpec
 
   if sfThread in s.flags and t.gcUnsafe:
-    if optThreads in gGlobalOptions and optThreadAnalysis in gGlobalOptions:
+    if optThreads in g.config.globalOptions and optThreadAnalysis in g.config.globalOptions:
       #localError(s.info, "'$1' is not GC-safe" % s.name.s)
-      listGcUnsafety(s, onlyWarning=false)
+      listGcUnsafety(s, onlyWarning=false, g.config)
     else:
-      listGcUnsafety(s, onlyWarning=true)
+      listGcUnsafety(s, onlyWarning=true, g.config)
       #localError(s.info, warnGcUnsafe2, s.name.s)
   if sfNoSideEffect in s.flags and t.hasSideEffect:
     when false:
-      listGcUnsafety(s, onlyWarning=false)
+      listGcUnsafety(s, onlyWarning=false, g.config)
     else:
-      localError(s.info, errXhasSideEffects, s.name.s)
+      localError(g.config, s.info, "'$1' can have side effects" % s.name.s)
   if not t.gcUnsafe:
     s.typ.flags.incl tfGcSafe
   if not t.hasSideEffect and sfSideEffect notin s.flags:
@@ -976,7 +979,7 @@ proc trackProc*(s: PSym, body: PNode) =
     s.typ.lockLevel = t.maxLockLevel
   elif t.maxLockLevel > s.typ.lockLevel:
     #localError(s.info,
-    message(s.info, warnLockLevel,
+    message(g.config, s.info, warnLockLevel,
       "declared lock level is $1, but real lock level is $2" %
         [$s.typ.lockLevel, $t.maxLockLevel])
   when defined(useDfa):
@@ -984,12 +987,12 @@ proc trackProc*(s: PSym, body: PNode) =
       dataflowAnalysis(s, body)
       when false: trackWrites(s, body)
 
-proc trackTopLevelStmt*(module: PSym; n: PNode) =
+proc trackTopLevelStmt*(g: ModuleGraph; module: PSym; n: PNode) =
   if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, nkFuncDef,
                 nkTypeSection, nkConverterDef, nkMethodDef, nkIteratorDef}:
     return
   var effects = newNode(nkEffectList, n.info)
   var t: TEffects
-  initEffects(effects, module, t)
+  initEffects(g, effects, module, t)
   t.isToplevel = true
   track(t, n)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 9f00e877f..3687e50e9 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -10,51 +10,77 @@
 ## this module does the semantic checking of statements
 #  included from sem.nim
 
-var enforceVoidContext = PType(kind: tyStmt)
+const
+  errNoSymbolToBorrowFromFound = "no symbol to borrow from found"
+  errDiscardValueX = "value of type '$1' has to be discarded"
+  errInvalidDiscard = "statement returns no value that can be discarded"
+  errInvalidControlFlowX = "invalid control flow: $1"
+  errSelectorMustBeOfCertainTypes = "selector must be of an ordinal type, float or string"
+  errExprCannotBeRaised = "only a 'ref object' can be raised"
+  errBreakOnlyInLoop = "'break' only allowed in loop construct"
+  errExceptionAlreadyHandled = "exception already handled"
+  errYieldNotAllowedHere = "'yield' only allowed in an iterator"
+  errYieldNotAllowedInTryStmt = "'yield' cannot be used within 'try' in a non-inlined iterator"
+  errInvalidNumberOfYieldExpr = "invalid number of 'yield' expressions"
+  errCannotReturnExpr = "current routine cannot return an expression"
+  errGenericLambdaNotAllowed = "A nested proc can have generic parameters only when " &
+    "it is used as an operand to another routine and the types " &
+    "of the generic paramers can be inferred from the expected signature."
+  errCannotInferTypeOfTheLiteral = "cannot infer the type of the $1"
+  errCannotInferReturnType = "cannot infer the return type of the proc"
+  errCannotInferStaticParam = "cannot infer the value of the static param '$1'"
+  errProcHasNoConcreteType = "'$1' doesn't have a concrete type, due to unspecified generic parameters."
+  errLetNeedsInit = "'let' symbol requires an initialization"
+  errThreadvarCannotInit = "a thread var cannot be initialized explicitly; this would only run for the main thread"
+  errImplOfXexpected = "implementation of '$1' expected"
+  errRecursiveDependencyX = "recursive dependency: '$1'"
+  errPragmaOnlyInHeaderOfProcX = "pragmas are only allowed in the header of a proc; redefinition of $1"
+
+var enforceVoidContext = PType(kind: tyStmt) # XXX global variable here
 
 proc semDiscard(c: PContext, n: PNode): PNode =
   result = n
-  checkSonsLen(n, 1)
+  checkSonsLen(n, 1, c.config)
   if n.sons[0].kind != nkEmpty:
     n.sons[0] = semExprWithType(c, n.sons[0])
     if isEmptyType(n.sons[0].typ) or n.sons[0].typ.kind == tyNone or n.sons[0].kind == nkTypeOfExpr:
-      localError(n.info, errInvalidDiscard)
+      localError(c.config, n.info, errInvalidDiscard)
 
 proc semBreakOrContinue(c: PContext, n: PNode): PNode =
   result = n
-  checkSonsLen(n, 1)
+  checkSonsLen(n, 1, c.config)
   if n.sons[0].kind != nkEmpty:
     if n.kind != nkContinueStmt:
       var s: PSym
       case n.sons[0].kind
       of nkIdent: s = lookUp(c, n.sons[0])
       of nkSym: s = n.sons[0].sym
-      else: illFormedAst(n)
+      else: illFormedAst(n, c.config)
       s = getGenSym(c, s)
       if s.kind == skLabel and s.owner.id == c.p.owner.id:
         var x = newSymNode(s)
         x.info = n.info
         incl(s.flags, sfUsed)
         n.sons[0] = x
-        suggestSym(x.info, s, c.graph.usageSym)
+        suggestSym(c.config, x.info, s, c.graph.usageSym)
         styleCheckUse(x.info, s)
       else:
-        localError(n.info, errInvalidControlFlowX, s.name.s)
+        localError(c.config, n.info, errInvalidControlFlowX % s.name.s)
     else:
-      localError(n.info, errGenerated, "'continue' cannot have a label")
+      localError(c.config, n.info, errGenerated, "'continue' cannot have a label")
   elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
-    localError(n.info, errInvalidControlFlowX,
+    localError(c.config, n.info, errInvalidControlFlowX %
                renderTree(n, {renderNoComments}))
 
-proc semAsm(con: PContext, n: PNode): PNode =
-  checkSonsLen(n, 2)
-  var marker = pragmaAsm(con, n.sons[0])
+proc semAsm(c: PContext, n: PNode): PNode =
+  checkSonsLen(n, 2, c.config)
+  var marker = pragmaAsm(c, n.sons[0])
   if marker == '\0': marker = '`' # default marker
-  result = semAsmOrEmit(con, n, marker)
+  result = semAsmOrEmit(c, n, marker)
 
 proc semWhile(c: PContext, n: PNode): PNode =
   result = n
-  checkSonsLen(n, 2)
+  checkSonsLen(n, 2, c.config)
   openScope(c)
   n.sons[0] = forceBool(c, semExprWithType(c, n.sons[0]))
   inc(c.p.nestedLoopCounter)
@@ -95,13 +121,13 @@ proc implicitlyDiscardable(n: PNode): bool =
   result = isCallExpr(n) and n.sons[0].kind == nkSym and
            sfDiscardable in n.sons[0].sym.flags
 
-proc fixNilType(n: PNode) =
+proc fixNilType(c: PContext; n: PNode) =
   if isAtom(n):
     if n.kind != nkNilLit and n.typ != nil:
-      localError(n.info, errDiscardValueX, n.typ.typeToString)
+      localError(c.config, n.info, errDiscardValueX % n.typ.typeToString)
   elif n.kind in {nkStmtList, nkStmtListExpr}:
     n.kind = nkStmtList
-    for it in n: fixNilType(it)
+    for it in n: fixNilType(c, it)
   n.typ = nil
 
 proc discardCheck(c: PContext, result: PNode) =
@@ -113,7 +139,7 @@ proc discardCheck(c: PContext, result: PNode) =
       while n.kind in skipForDiscardable:
         n = n.lastSon
         n.typ = nil
-    elif result.typ.kind != tyError and gCmd != cmdInteractive:
+    elif result.typ.kind != tyError and c.config.cmd != cmdInteractive:
       var n = result
       while n.kind in skipForDiscardable: n = n.lastSon
       var s = "expression '" & $n & "' is of type '" &
@@ -123,7 +149,7 @@ proc discardCheck(c: PContext, result: PNode) =
         s.add "; start of expression here: " & $result.info
       if result.typ.kind == tyProc:
         s.add "; for a function call use ()"
-      localError(n.info, s)
+      localError(c.config, n.info, s)
 
 proc semIf(c: PContext, n: PNode): PNode =
   result = n
@@ -142,7 +168,7 @@ proc semIf(c: PContext, n: PNode): PNode =
       hasElse = true
       it.sons[0] = semExprBranchScope(c, it.sons[0])
       typ = commonType(typ, it.sons[0])
-    else: illFormedAst(it)
+    else: illFormedAst(it, c.config)
   if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse:
     for it in n: discardCheck(c, it.lastSon)
     result.kind = nkIfStmt
@@ -158,7 +184,7 @@ proc semIf(c: PContext, n: PNode): PNode =
 
 proc semCase(c: PContext, n: PNode): PNode =
   result = n
-  checkMinSonsLen(n, 2)
+  checkMinSonsLen(n, 2, c.config)
   openScope(c)
   n.sons[0] = semExprWithType(c, n.sons[0])
   var chckCovered = false
@@ -172,23 +198,23 @@ proc semCase(c: PContext, n: PNode): PNode =
   of tyFloat..tyFloat128, tyString, tyError:
     discard
   else:
-    localError(n.info, errSelectorMustBeOfCertainTypes)
+    localError(c.config, n.info, errSelectorMustBeOfCertainTypes)
     return
   for i in countup(1, sonsLen(n) - 1):
     var x = n.sons[i]
     when defined(nimsuggest):
-      if gIdeCmd == ideSug and exactEquals(gTrackPos, x.info) and caseTyp.kind == tyEnum:
+      if c.config.ideCmd == ideSug and exactEquals(gTrackPos, x.info) and caseTyp.kind == tyEnum:
         suggestEnum(c, x, caseTyp)
     case x.kind
     of nkOfBranch:
-      checkMinSonsLen(x, 2)
+      checkMinSonsLen(x, 2, c.config)
       semCaseBranch(c, n, x, i, covered)
       var last = sonsLen(x)-1
       x.sons[last] = semExprBranchScope(c, x.sons[last])
       typ = commonType(typ, x.sons[last])
     of nkElifBranch:
       chckCovered = false
-      checkSonsLen(x, 2)
+      checkSonsLen(x, 2, c.config)
       when newScopeForIf: openScope(c)
       x.sons[0] = forceBool(c, semExprWithType(c, x.sons[0]))
       when not newScopeForIf: openScope(c)
@@ -197,17 +223,17 @@ proc semCase(c: PContext, n: PNode): PNode =
       closeScope(c)
     of nkElse:
       chckCovered = false
-      checkSonsLen(x, 1)
+      checkSonsLen(x, 1, c.config)
       x.sons[0] = semExprBranchScope(c, x.sons[0])
       typ = commonType(typ, x.sons[0])
       hasElse = true
     else:
-      illFormedAst(x)
+      illFormedAst(x, c.config)
   if chckCovered:
     if covered == toCover(n.sons[0].typ):
       hasElse = true
     else:
-      localError(n.info, errNotAllCasesCovered)
+      localError(c.config, n.info, "not all cases are covered")
   closeScope(c)
   if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse:
     for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
@@ -229,19 +255,19 @@ proc semTry(c: PContext, n: PNode): PNode =
     # returns true if exception type is imported type
     let typ = semTypeNode(c, typeNode, nil).toObject()
     var is_imported = false
-    if isImportedException(typ):
+    if isImportedException(typ, c.config):
       is_imported = true
     elif not isException(typ):
-      localError(typeNode.info, errExprCannotBeRaised)
+      localError(c.config, typeNode.info, errExprCannotBeRaised)
 
     if containsOrIncl(check, typ.id):
-      localError(typeNode.info, errExceptionAlreadyHandled)
+      localError(c.config, typeNode.info, errExceptionAlreadyHandled)
     typeNode = newNodeIT(nkType, typeNode.info, typ)
     is_imported
 
   result = n
   inc c.p.inTryStmt
-  checkMinSonsLen(n, 2)
+  checkMinSonsLen(n, 2, c.config)
 
   var typ = commonTypeBegin
   n[0] = semExprBranchScope(c, n[0])
@@ -250,7 +276,7 @@ proc semTry(c: PContext, n: PNode): PNode =
   var last = sonsLen(n) - 1
   for i in countup(1, last):
     let a = n.sons[i]
-    checkMinSonsLen(a, 1)
+    checkMinSonsLen(a, 1, c.config)
     openScope(c)
     if a.kind == nkExceptBranch:
 
@@ -277,10 +303,10 @@ proc semTry(c: PContext, n: PNode): PNode =
           else: is_native = true
 
         if is_native and is_imported:
-          localError(a[0].info, "Mix of imported and native exception types is not allowed in one except branch")
+          localError(c.config, a[0].info, "Mix of imported and native exception types is not allowed in one except branch")
 
     elif a.kind != nkFinally:
-      illFormedAst(n)
+      illFormedAst(n, c.config)
 
     # last child of an nkExcept/nkFinally branch is a statement:
     a[^1] = semExprBranchScope(c, a[^1])
@@ -312,10 +338,10 @@ proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
       result.info = n.info
       result.typ = typ
     else:
-      changeType(r1, typ, check=true)
+      changeType(c, r1, typ, check=true)
       result = r1
   elif not sameType(result.typ, typ):
-    changeType(result, typ, check=false)
+    changeType(c, result, typ, check=false)
 
 proc findShadowedVar(c: PContext, v: PSym): PSym =
   for scope in walkScopes(c.currentScope.parent):
@@ -339,16 +365,16 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
     result = semIdentWithPragma(c, kind, n, {})
     if result.owner.kind == skModule:
       incl(result.flags, sfGlobal)
-  suggestSym(n.info, result, c.graph.usageSym)
+  suggestSym(c.config, n.info, result, c.graph.usageSym)
   styleCheckDef(result)
 
-proc checkNilable(v: PSym) =
+proc checkNilable(c: PContext; v: PSym) =
   if {sfGlobal, sfImportC} * v.flags == {sfGlobal} and
       {tfNotNil, tfNeedsInit} * v.typ.flags != {}:
     if v.ast.isNil:
-      message(v.info, warnProveInit, v.name.s)
+      message(c.config, v.info, warnProveInit, v.name.s)
     elif tfNotNil in v.typ.flags and tfNotNil notin v.ast.typ.flags:
-      message(v.info, warnProveInit, v.name.s)
+      message(c.config, v.info, warnProveInit, v.name.s)
 
 include semasgn
 
@@ -369,13 +395,13 @@ proc isDiscardUnderscore(v: PSym): bool =
 
 proc semUsing(c: PContext; n: PNode): PNode =
   result = ast.emptyNode
-  if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "using")
+  if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "using")
   for i in countup(0, sonsLen(n)-1):
     var a = n.sons[i]
-    if gCmd == cmdIdeTools: suggestStmt(c, a)
+    if c.config.cmd == cmdIdeTools: suggestStmt(c, a)
     if a.kind == nkCommentStmt: continue
-    if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a)
-    checkMinSonsLen(a, 3)
+    if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a, c.config)
+    checkMinSonsLen(a, 3, c.config)
     var length = sonsLen(a)
     if a.sons[length-2].kind != nkEmpty:
       let typ = semTypeNode(c, a.sons[length-2], nil)
@@ -384,10 +410,10 @@ proc semUsing(c: PContext; n: PNode): PNode =
         v.typ = typ
         strTableIncl(c.signatures, v)
     else:
-      localError(a.info, "'using' section must have a type")
+      localError(c.config, a.info, "'using' section must have a type")
     var def: PNode
     if a.sons[length-1].kind != nkEmpty:
-      localError(a.info, "'using' sections cannot contain assignments")
+      localError(c.config, a.info, "'using' sections cannot contain assignments")
 
 proc hasEmpty(typ: PType): bool =
   if typ.kind in {tySequence, tyArray, tySet}:
@@ -416,7 +442,7 @@ proc makeDeref(n: PNode): PNode =
 proc fillPartialObject(c: PContext; n: PNode; typ: PType) =
   if n.len == 2:
     let x = semExprWithType(c, n[0])
-    let y = considerQuotedIdent(n[1])
+    let y = considerQuotedIdent(c.config, n[1])
     let obj = x.typ.skipTypes(abstractPtrs)
     if obj.kind == tyObject and tfPartial in obj.flags:
       let field = newSym(skField, getIdent(y.s), obj.sym, n[1].info)
@@ -427,14 +453,14 @@ proc fillPartialObject(c: PContext; n: PNode; typ: PType) =
       n.sons[1] = newSymNode(field)
       n.typ = field.typ
     else:
-      localError(n.info, "implicit object field construction " &
+      localError(c.config, n.info, "implicit object field construction " &
         "requires a .partial object, but got " & typeToString(obj))
   else:
-    localError(n.info, "nkDotNode requires 2 children")
+    localError(c.config, n.info, "nkDotNode requires 2 children")
 
-proc setVarType(v: PSym, typ: PType) =
+proc setVarType(c: PContext; v: PSym, typ: PType) =
   if v.typ != nil and not sameTypeOrNil(v.typ, typ):
-    localError(v.info, "inconsistent typing for reintroduced symbol '" &
+    localError(c.config, v.info, "inconsistent typing for reintroduced symbol '" &
         v.name.s & "': previous type was: " & typeToString(v.typ) &
         "; new type is: " & typeToString(typ))
   v.typ = typ
@@ -445,10 +471,10 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
   var hasCompileTime = false
   for i in countup(0, sonsLen(n)-1):
     var a = n.sons[i]
-    if gCmd == cmdIdeTools: suggestStmt(c, a)
+    if c.config.cmd == cmdIdeTools: suggestStmt(c, a)
     if a.kind == nkCommentStmt: continue
-    if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a)
-    checkMinSonsLen(a, 3)
+    if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a, c.config)
+    checkMinSonsLen(a, 3, c.config)
     var length = sonsLen(a)
     var typ: PType
     if a.sons[length-2].kind != nkEmpty:
@@ -460,7 +486,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
       def = semExprWithType(c, a.sons[length-1], {efAllowDestructor})
       if def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro:
         # prevent the all too common 'var x = int' bug:
-        localError(def.info, "'typedesc' metatype is not valid here; typed '=' instead of ':'?")
+        localError(c.config, def.info, "'typedesc' metatype is not valid here; typed '=' instead of ':'?")
         def.typ = errorType(c)
       if typ != nil:
         if typ.isMetaType:
@@ -476,23 +502,23 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
         if typ.kind in tyUserTypeClasses and typ.isResolvedUserTypeClass:
           typ = typ.lastSon
         if hasEmpty(typ):
-          localError(def.info, errCannotInferTypeOfTheLiteral,
+          localError(c.config, def.info, errCannotInferTypeOfTheLiteral %
                      ($typ.kind).substr(2).toLowerAscii)
         elif typ.kind == tyProc and tfUnresolved in typ.flags:
-          localError(def.info, errProcHasNoConcreteType, def.renderTree)
+          localError(c.config, def.info, errProcHasNoConcreteType % def.renderTree)
     else:
-      if symkind == skLet: localError(a.info, errLetNeedsInit)
+      if symkind == skLet: localError(c.config, a.info, errLetNeedsInit)
 
     # this can only happen for errornous var statements:
     if typ == nil: continue
-    typeAllowedCheck(a.info, typ, symkind, if c.matchedConcept != nil: {taConcept} else: {})
+    typeAllowedCheck(c.config, a.info, typ, symkind, if c.matchedConcept != nil: {taConcept} else: {})
     liftTypeBoundOps(c, typ, a.info)
     var tup = skipTypes(typ, {tyGenericInst, tyAlias, tySink})
     if a.kind == nkVarTuple:
       if tup.kind != tyTuple:
-        localError(a.info, errXExpected, "tuple")
+        localError(c.config, a.info, errXExpected, "tuple")
       elif length-2 != sonsLen(tup):
-        localError(a.info, errWrongNumberOfVariables)
+        localError(c.config, a.info, errWrongNumberOfVariables)
       b = newNodeI(nkVarTuple, a.info)
       newSons(b, length)
       b.sons[length-2] = a.sons[length-2] # keep type desc for doc generator
@@ -500,7 +526,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
       addToVarSection(c, result, n, b)
     elif tup.kind == tyTuple and def.kind in {nkPar, nkTupleConstr} and
         a.kind == nkIdentDefs and a.len > 3:
-      message(a.info, warnEachIdentIsTuple)
+      message(c.config, a.info, warnEachIdentIsTuple)
 
     for j in countup(0, length-3):
       if a[j].kind == nkDotExpr:
@@ -518,19 +544,19 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
           if shadowed != nil:
             shadowed.flags.incl(sfShadowed)
             if shadowed.kind == skResult and sfGenSym notin v.flags:
-              message(a.info, warnResultShadowed)
+              message(c.config, a.info, warnResultShadowed)
             # a shadowed variable is an error unless it appears on the right
             # side of the '=':
-            if warnShadowIdent in gNotes and not identWithin(def, v.name):
-              message(a.info, warnShadowIdent, v.name.s)
+            if warnShadowIdent in c.config.notes and not identWithin(def, v.name):
+              message(c.config, a.info, warnShadowIdent, v.name.s)
       if a.kind != nkVarTuple:
         if def.kind != nkEmpty:
           # this is needed for the evaluation pass and for the guard checking:
           v.ast = def
-          if sfThread in v.flags: localError(def.info, errThreadvarCannotInit)
-        setVarType(v, typ)
+          if sfThread in v.flags: localError(c.config, def.info, errThreadvarCannotInit)
+        setVarType(c, v, typ)
         b = newNodeI(nkIdentDefs, a.info)
-        if importantComments():
+        if importantComments(c.config):
           # keep documentation information:
           b.comment = a.comment
         addSon(b, newSymNode(v))
@@ -540,29 +566,29 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
       else:
         if def.kind in {nkPar, nkTupleConstr}: v.ast = def[j]
         # bug #7663, for 'nim check' this can be a non-tuple:
-        if tup.kind == tyTuple: setVarType(v, tup.sons[j])
+        if tup.kind == tyTuple: setVarType(c, v, tup.sons[j])
         else: v.typ = tup
         b.sons[j] = newSymNode(v)
-      checkNilable(v)
+      checkNilable(c, v)
       if sfCompileTime in v.flags: hasCompileTime = true
   if hasCompileTime:
-    vm.setupCompileTimeVar(c.module, c.cache, c.graph.config, result)
+    vm.setupCompileTimeVar(c.module, c.cache, c.graph, result)
 
 proc semConst(c: PContext, n: PNode): PNode =
   result = copyNode(n)
   for i in countup(0, sonsLen(n) - 1):
     var a = n.sons[i]
-    if gCmd == cmdIdeTools: suggestStmt(c, a)
+    if c.config.cmd == cmdIdeTools: suggestStmt(c, a)
     if a.kind == nkCommentStmt: continue
-    if (a.kind != nkConstDef): illFormedAst(a)
-    checkSonsLen(a, 3)
+    if a.kind != nkConstDef: illFormedAst(a, c.config)
+    checkSonsLen(a, 3, c.config)
     var v = semIdentDef(c, a.sons[0], skConst)
     var typ: PType = nil
     if a.sons[1].kind != nkEmpty: typ = semTypeNode(c, a.sons[1], nil)
 
     var def = semConstExpr(c, a.sons[2])
     if def == nil:
-      localError(a.sons[2].info, errConstExprExpected)
+      localError(c.config, a.sons[2].info, errConstExprExpected)
       continue
     # check type compatibility between def.typ and typ:
     if typ != nil:
@@ -570,16 +596,16 @@ proc semConst(c: PContext, n: PNode): PNode =
     else:
       typ = def.typ
     if typ == nil:
-      localError(a.sons[2].info, errConstExprExpected)
+      localError(c.config, a.sons[2].info, errConstExprExpected)
       continue
     if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit:
-      localError(a.info, "invalid type for const: " & typeToString(typ))
+      localError(c.config, a.info, "invalid type for const: " & typeToString(typ))
       continue
-    setVarType(v, typ)
+    setVarType(c, v, typ)
     v.ast = def               # no need to copy
     if sfGenSym notin v.flags: addInterfaceDecl(c, v)
     var b = newNodeI(nkConstDef, a.info)
-    if importantComments(): b.comment = a.comment
+    if importantComments(c.config): b.comment = a.comment
     addSon(b, newSymNode(v))
     addSon(b, a.sons[1])
     addSon(b, copyTree(def))
@@ -588,12 +614,12 @@ proc semConst(c: PContext, n: PNode): PNode =
 include semfields
 
 proc addForVarDecl(c: PContext, v: PSym) =
-  if warnShadowIdent in gNotes:
+  if warnShadowIdent in c.config.notes:
     let shadowed = findShadowedVar(c, v)
     if shadowed != nil:
       # XXX should we do this here?
       #shadowed.flags.incl(sfShadowed)
-      message(v.info, warnShadowIdent, v.name.s)
+      message(c.config, v.info, warnShadowIdent, v.name.s)
   addDecl(c, v)
 
 proc symForVar(c: PContext, n: PNode): PSym =
@@ -619,9 +645,9 @@ proc semForVars(c: PContext, n: PNode): PNode =
       n.sons[0] = newSymNode(v)
       if sfGenSym notin v.flags: addForVarDecl(c, v)
     else:
-      localError(n.info, errWrongNumberOfVariables)
+      localError(c.config, n.info, errWrongNumberOfVariables)
   elif length-2 != sonsLen(iter):
-    localError(n.info, errWrongNumberOfVariables)
+    localError(c.config, n.info, errWrongNumberOfVariables)
   else:
     for i in countup(0, length - 3):
       var v = symForVar(c, n.sons[i])
@@ -658,7 +684,7 @@ proc handleForLoopMacro(c: PContext; n: PNode): PNode =
     # n := for a, b, c in m(x, y, z): Y
     # to
     # m(n)
-    let forLoopStmt = magicsys.getCompilerProc("ForLoopStmt")
+    let forLoopStmt = magicsys.getCompilerProc(c.graph, "ForLoopStmt")
     if forLoopStmt == nil: return
 
     let headSymbol = iterExpr[0]
@@ -671,7 +697,7 @@ proc handleForLoopMacro(c: PContext; n: PNode): PNode =
           if match == nil:
             match = symx
           else:
-            localError(n.info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
+            localError(c.config, n.info, errAmbiguousCallXYZ % [
               getProcHeader(match), getProcHeader(symx), $iterExpr])
       symx = nextOverloadIter(o, c, headSymbol)
 
@@ -685,7 +711,7 @@ proc handleForLoopMacro(c: PContext; n: PNode): PNode =
     else: result = nil
 
 proc semFor(c: PContext, n: PNode): PNode =
-  checkMinSonsLen(n, 3)
+  checkMinSonsLen(n, 3, c.config)
   var length = sonsLen(n)
   result = handleForLoopMacro(c, n)
   if result != nil: return result
@@ -715,7 +741,7 @@ proc semFor(c: PContext, n: PNode): PNode =
     elif length == 4:
       n.sons[length-2] = implicitIterator(c, "pairs", n.sons[length-2])
     else:
-      localError(n.sons[length-2].info, errIteratorExpected)
+      localError(c.config, n.sons[length-2].info, "iterator within for loop context expected")
     result = semForVars(c, n)
   else:
     result = semForVars(c, n)
@@ -726,31 +752,31 @@ proc semFor(c: PContext, n: PNode): PNode =
 
 proc semRaise(c: PContext, n: PNode): PNode =
   result = n
-  checkSonsLen(n, 1)
+  checkSonsLen(n, 1, c.config)
   if n[0].kind != nkEmpty:
     n[0] = semExprWithType(c, n[0])
     let typ = n[0].typ
-    if not isImportedException(typ):
+    if not isImportedException(typ, c.config):
       if typ.kind != tyRef or typ.lastSon.kind != tyObject:
-        localError(n.info, errExprCannotBeRaised)
+        localError(c.config, n.info, errExprCannotBeRaised)
       if not isException(typ.lastSon):
-        localError(n.info, "raised object of type $1 does not inherit from Exception",
+        localError(c.config, n.info, "raised object of type $1 does not inherit from Exception",
                           [typeToString(typ)])
 
 proc addGenericParamListToScope(c: PContext, n: PNode) =
-  if n.kind != nkGenericParams: illFormedAst(n)
+  if n.kind != nkGenericParams: illFormedAst(n, c.config)
   for i in countup(0, sonsLen(n)-1):
     var a = n.sons[i]
     if a.kind == nkSym: addDecl(c, a.sym)
-    else: illFormedAst(a)
+    else: illFormedAst(a, c.config)
 
-proc typeSectionTypeName(n: PNode): PNode =
+proc typeSectionTypeName(c: PContext; n: PNode): PNode =
   if n.kind == nkPragmaExpr:
-    if n.len == 0: illFormedAst(n)
+    if n.len == 0: illFormedAst(n, c.config)
     result = n.sons[0]
   else:
     result = n
-  if result.kind != nkSym: illFormedAst(n)
+  if result.kind != nkSym: illFormedAst(n, c.config)
 
 
 proc typeSectionLeftSidePass(c: PContext, n: PNode) =
@@ -759,21 +785,21 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
   for i in countup(0, sonsLen(n) - 1):
     var a = n.sons[i]
     when defined(nimsuggest):
-      if gCmd == cmdIdeTools:
+      if c.config.cmd == cmdIdeTools:
         inc c.inTypeContext
         suggestStmt(c, a)
         dec c.inTypeContext
     if a.kind == nkCommentStmt: continue
-    if a.kind != nkTypeDef: illFormedAst(a)
-    checkSonsLen(a, 3)
+    if a.kind != nkTypeDef: illFormedAst(a, c.config)
+    checkSonsLen(a, 3, c.config)
     let name = a.sons[0]
     var s: PSym
     if name.kind == nkDotExpr and a[2].kind == nkObjectTy:
-      let pkgName = considerQuotedIdent(name[0])
-      let typName = considerQuotedIdent(name[1])
+      let pkgName = considerQuotedIdent(c.config, name[0])
+      let typName = considerQuotedIdent(c.config, name[1])
       let pkg = c.graph.packageSyms.strTableGet(pkgName)
       if pkg.isNil or pkg.kind != skPackage:
-        localError(name.info, "unknown package name: " & pkgName.s)
+        localError(c.config, name.info, "unknown package name: " & pkgName.s)
       else:
         let typsym = pkg.tab.strTableGet(typName)
         if typsym.isNil:
@@ -787,7 +813,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
           s = typsym
           addInterfaceDecl(c, s)
         else:
-          localError(name.info, typsym.name.s & " is not a type that can be forwarded")
+          localError(c.config, name.info, typsym.name.s & " is not a type that can be forwarded")
           s = typsym
     else:
       s = semIdentDef(c, name, skType)
@@ -799,7 +825,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
         # check if the symbol already exists:
         let pkg = c.module.owner
         if not isTopLevel(c) or pkg.isNil:
-          localError(name.info, "only top level types in a package can be 'package'")
+          localError(c.config, name.info, "only top level types in a package can be 'package'")
         else:
           let typsym = pkg.tab.strTableGet(s.name)
           if typsym != nil:
@@ -807,7 +833,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
               typeCompleted(typsym)
               typsym.info = s.info
             else:
-              localError(name.info, "cannot complete type '" & s.name.s & "' twice; " &
+              localError(c.config, name.info, "cannot complete type '" & s.name.s & "' twice; " &
                       "previous type completion was here: " & $typsym.info)
             s = typsym
       # add it here, so that recursive types are possible:
@@ -818,14 +844,12 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
     else:
       a.sons[0] = newSymNode(s)
 
-proc checkCovariantParamsUsages(genericType: PType) =
+proc checkCovariantParamsUsages(c: PContext; genericType: PType) =
   var body = genericType[^1]
 
-  proc traverseSubTypes(t: PType): bool =
-    template error(msg) = localError(genericType.sym.info, msg)
-
+  proc traverseSubTypes(c: PContext; t: PType): bool =
+    template error(msg) = localError(c.config, genericType.sym.info, msg)
     result = false
-
     template subresult(r) =
       let sub = r
       result = result or sub
@@ -834,24 +858,19 @@ proc checkCovariantParamsUsages(genericType: PType) =
     of tyGenericParam:
       t.flags.incl tfWeakCovariant
       return true
-
     of tyObject:
       for field in t.n:
-        subresult traverseSubTypes(field.typ)
-
+        subresult traverseSubTypes(c, field.typ)
     of tyArray:
-      return traverseSubTypes(t[1])
-
+      return traverseSubTypes(c, t[1])
     of tyProc:
       for subType in t.sons:
         if subType != nil:
-          subresult traverseSubTypes(subType)
+          subresult traverseSubTypes(c, subType)
       if result:
         error("non-invariant type param used in a proc type: " & $t)
-
     of tySequence:
-      return traverseSubTypes(t[0])
-
+      return traverseSubTypes(c, t[0])
     of tyGenericInvocation:
       let targetBody = t[0]
       for i in 1 ..< t.len:
@@ -872,43 +891,35 @@ proc checkCovariantParamsUsages(genericType: PType) =
                     "' used in a non-contravariant position")
             result = true
         else:
-          subresult traverseSubTypes(param)
-
+          subresult traverseSubTypes(c, param)
     of tyAnd, tyOr, tyNot, tyStatic, tyBuiltInTypeClass, tyCompositeTypeClass:
       error("non-invariant type parameters cannot be used with types such '" & $t & "'")
-
     of tyUserTypeClass, tyUserTypeClassInst:
       error("non-invariant type parameters are not supported in concepts")
-
     of tyTuple:
       for fieldType in t.sons:
-        subresult traverseSubTypes(fieldType)
-
+        subresult traverseSubTypes(c, fieldType)
     of tyPtr, tyRef, tyVar, tyLent:
       if t.base.kind == tyGenericParam: return true
-      return traverseSubTypes(t.base)
-
+      return traverseSubTypes(c, t.base)
     of tyDistinct, tyAlias, tySink:
-      return traverseSubTypes(t.lastSon)
-
+      return traverseSubTypes(c, t.lastSon)
     of tyGenericInst:
-      internalAssert false
-
+      internalAssert c.config, false
     else:
       discard
-
-  discard traverseSubTypes(body)
+  discard traverseSubTypes(c, body)
 
 proc typeSectionRightSidePass(c: PContext, n: PNode) =
   for i in countup(0, sonsLen(n) - 1):
     var a = n.sons[i]
     if a.kind == nkCommentStmt: continue
-    if (a.kind != nkTypeDef): illFormedAst(a)
-    checkSonsLen(a, 3)
-    let name = typeSectionTypeName(a.sons[0])
+    if a.kind != nkTypeDef: illFormedAst(a, c.config)
+    checkSonsLen(a, 3, c.config)
+    let name = typeSectionTypeName(c, a.sons[0])
     var s = name.sym
     if s.magic == mNone and a.sons[2].kind == nkEmpty:
-      localError(a.info, errImplOfXexpected, s.name.s)
+      localError(c.config, a.info, errImplOfXexpected % s.name.s)
     if s.magic != mNone: processMagicType(c, s)
     if a.sons[1].kind != nkEmpty:
       # We have a generic type declaration here. In generic types,
@@ -939,7 +950,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
         body.size = -1 # could not be computed properly
         s.typ.sons[sonsLen(s.typ) - 1] = body
         if tfCovariant in s.typ.flags:
-          checkCovariantParamsUsages(s.typ)
+          checkCovariantParamsUsages(c, s.typ)
           # XXX: This is a temporary limitation:
           # The codegen currently produces various failures with
           # generic imported types that have fields, but we need
@@ -974,8 +985,8 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
       # give anonymous object a dummy symbol:
       var st = s.typ
       if st.kind == tyGenericBody: st = st.lastSon
-      internalAssert st.kind in {tyPtr, tyRef}
-      internalAssert st.lastSon.sym == nil
+      internalAssert c.config, st.kind in {tyPtr, tyRef}
+      internalAssert c.config, st.lastSon.sym == nil
       incl st.flags, tfRefsAnonObj
       let obj = newSym(skType, getIdent(s.name.s & ":ObjectType"),
                               getCurrOwner(c), s.info)
@@ -983,17 +994,17 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
       st.lastSon.sym = obj
 
 
-proc checkForMetaFields(n: PNode) =
+proc checkForMetaFields(c: PContext; n: PNode) =
   template checkMeta(t) =
     if t != nil and t.isMetaType and tfGenericTypeParam notin t.flags:
-      localError(n.info, errTIsNotAConcreteType, t.typeToString)
+      localError(c.config, n.info, errTIsNotAConcreteType % t.typeToString)
 
   if n.isNil: return
   case n.kind
   of nkRecList, nkRecCase:
-    for s in n: checkForMetaFields(s)
+    for s in n: checkForMetaFields(c, s)
   of nkOfBranch, nkElse:
-    checkForMetaFields(n.lastSon)
+    checkForMetaFields(c, n.lastSon)
   of nkSym:
     let t = n.sym.typ
     case t.kind
@@ -1005,13 +1016,13 @@ proc checkForMetaFields(n: PNode) =
     else:
       checkMeta(t)
   else:
-    internalAssert false
+    internalAssert c.config, false
 
 proc typeSectionFinalPass(c: PContext, n: PNode) =
   for i in countup(0, sonsLen(n) - 1):
     var a = n.sons[i]
     if a.kind == nkCommentStmt: continue
-    let name = typeSectionTypeName(a.sons[0])
+    let name = typeSectionTypeName(c, a.sons[0])
     var s = name.sym
     # compute the type's size and check for illegal recursions:
     if a.sons[1].kind == nkEmpty:
@@ -1031,9 +1042,9 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
             assert s.typ != nil
             assignType(s.typ, t)
             s.typ.id = t.id     # same id
-      checkConstructedType(s.info, s.typ)
+      checkConstructedType(c.config, s.info, s.typ)
       if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil:
-        checkForMetaFields(s.typ.n)
+        checkForMetaFields(c, s.typ.n)
   instAllTypeBoundOp(c, n.info)
 
 
@@ -1042,10 +1053,10 @@ proc semAllTypeSections(c: PContext; n: PNode): PNode =
     case n.kind
     of nkIncludeStmt:
       for i in 0..<n.len:
-        var f = checkModuleName(n.sons[i])
+        var f = checkModuleName(c.config, n.sons[i])
         if f != InvalidFileIDX:
           if containsOrIncl(c.includedFiles, f.int):
-            localError(n.info, errRecursiveDependencyX, f.toFilename)
+            localError(c.config, n.info, errRecursiveDependencyX % f.toFilename)
           else:
             let code = gIncludeFile(c.graph, c.module, f, c.cache)
             gatherStmts c, code, result
@@ -1101,12 +1112,12 @@ proc semParamList(c: PContext, n, genericParams: PNode, s: PSym) =
   s.typ = semProcTypeNode(c, n, genericParams, nil, s.kind)
   if s.kind notin {skMacro, skTemplate}:
     if s.typ.sons[0] != nil and s.typ.sons[0].kind == tyStmt:
-      localError(n.info, errGenerated, "invalid return type: 'stmt'")
+      localError(c.config, n.info, "invalid return type: 'stmt'")
 
 proc addParams(c: PContext, n: PNode, kind: TSymKind) =
   for i in countup(1, sonsLen(n)-1):
     if n.sons[i].kind == nkSym: addParamOrResult(c, n.sons[i].sym, kind)
-    else: illFormedAst(n)
+    else: illFormedAst(n, c.config)
 
 proc semBorrow(c: PContext, n: PNode, s: PSym) =
   # search for the correct alias:
@@ -1115,7 +1126,7 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) =
     # store the alias:
     n.sons[bodyPos] = newSymNode(b)
   else:
-    localError(n.info, errNoSymbolToBorrowFromFound)
+    localError(c.config, n.info, errNoSymbolToBorrowFromFound)
 
 proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
   if t != nil:
@@ -1138,7 +1149,7 @@ proc lookupMacro(c: PContext, n: PNode): PSym =
     result = n.sym
     if result.kind notin {skMacro, skTemplate}: result = nil
   else:
-    result = searchInScopes(c, considerQuotedIdent(n), {skMacro, skTemplate})
+    result = searchInScopes(c, considerQuotedIdent(c.config, n), {skMacro, skTemplate})
 
 proc semProcAnnotation(c: PContext, prc: PNode;
                        validPragmas: TSpecialWords): PNode =
@@ -1150,11 +1161,11 @@ proc semProcAnnotation(c: PContext, prc: PNode;
     let m = lookupMacro(c, key)
     if m == nil:
       if key.kind == nkIdent and key.ident.id == ord(wDelegator):
-        if considerQuotedIdent(prc.sons[namePos]).s == "()":
+        if considerQuotedIdent(c.config, prc.sons[namePos]).s == "()":
           prc.sons[namePos] = newIdentNode(c.cache.idDelegator, prc.info)
           prc.sons[pragmasPos] = copyExcept(n, i)
         else:
-          localError(prc.info, errOnlyACallOpCanBeDelegator)
+          localError(c.config, prc.info, "only a call operator can be a delegator")
       continue
     elif sfCustomPragma in m.flags:
       continue # semantic check for custom pragma happens later in semProcAux
@@ -1199,7 +1210,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
   result = semProcAnnotation(c, n, lambdaPragmas)
   if result != nil: return result
   result = n
-  checkSonsLen(n, bodyPos + 1)
+  checkSonsLen(n, bodyPos + 1, c.config)
   var s: PSym
   if n[namePos].kind != nkSym:
     s = newSym(skProc, c.cache.idAnon, getCurrOwner(c), n.info)
@@ -1225,10 +1236,10 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
     s.typ = newProcType(c, n.info)
   if n.sons[pragmasPos].kind != nkEmpty:
     pragma(c, s, n.sons[pragmasPos], lambdaPragmas)
-  s.options = gOptions
+  s.options = c.config.options
   if n.sons[bodyPos].kind != nkEmpty:
     if sfImportc in s.flags:
-      localError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s)
+      localError(c.config, n.sons[bodyPos].info, errImplOfXNotAllowed % s.name.s)
     #if efDetermineType notin flags:
     # XXX not good enough; see tnamedparamanonproc.nim
     if gp.len == 0 or (gp.len == 1 and tfRetType in gp[0].typ.flags):
@@ -1236,13 +1247,13 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
       addResult(c, s.typ.sons[0], n.info, skProc)
       addResultNode(c, n)
       let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
-      n.sons[bodyPos] = transformBody(c.module, c.features, semBody, s)
+      n.sons[bodyPos] = transformBody(c.graph, c.module, semBody, s)
       popProcCon(c)
     elif efOperand notin flags:
-      localError(n.info, errGenericLambdaNotAllowed)
+      localError(c.config, n.info, errGenericLambdaNotAllowed)
     sideEffectsCheck(c, s)
   else:
-    localError(n.info, errImplOfXexpected, s.name.s)
+    localError(c.config, n.info, errImplOfXexpected % s.name.s)
   closeScope(c)           # close scope for parameters
   popOwner(c)
   result.typ = s.typ
@@ -1267,7 +1278,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
   for i in 1..<params.len:
     if params[i].typ.kind in {tyTypeDesc, tyGenericParam,
                               tyFromExpr}+tyTypeClasses:
-      localError(params[i].info, "cannot infer type of parameter: " &
+      localError(c.config, params[i].info, "cannot infer type of parameter: " &
                  params[i].sym.name.s)
     #params[i].sym.owner = s
   openScope(c)
@@ -1277,7 +1288,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
   addResult(c, n.typ.sons[0], n.info, skProc)
   addResultNode(c, n)
   let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
-  n.sons[bodyPos] = transformBody(c.module, c.features, semBody, s)
+  n.sons[bodyPos] = transformBody(c.graph, c.module, semBody, s)
   popProcCon(c)
   popOwner(c)
   closeScope(c)
@@ -1323,11 +1334,11 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
         if obj.destructor.isNil:
           obj.destructor = s
         else:
-          localError(n.info, errGenerated,
+          localError(c.config, n.info, errGenerated,
             "cannot bind another '" & s.name.s & "' to: " & typeToString(obj))
         noError = true
     if not noError and sfSystemModule notin s.owner.flags:
-      localError(n.info, errGenerated,
+      localError(c.config, n.info, errGenerated,
         "signature for '" & s.name.s & "' must be proc[T: object](x: var T)")
     incl(s.flags, sfUsed)
   of "deepcopy", "=deepcopy":
@@ -1344,13 +1355,13 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
       if t.kind in {tyObject, tyDistinct, tyEnum}:
         if t.deepCopy.isNil: t.deepCopy = s
         else:
-          localError(n.info, errGenerated,
+          localError(c.config, n.info, errGenerated,
                      "cannot bind another 'deepCopy' to: " & typeToString(t))
       else:
-        localError(n.info, errGenerated,
+        localError(c.config, n.info, errGenerated,
                    "cannot bind 'deepCopy' to: " & typeToString(t))
     else:
-      localError(n.info, errGenerated,
+      localError(c.config, n.info, errGenerated,
                  "signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T")
     incl(s.flags, sfUsed)
   of "=", "=sink":
@@ -1375,15 +1386,15 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
         if opr[].isNil:
           opr[] = s
         else:
-          localError(n.info, errGenerated,
+          localError(c.config, n.info, errGenerated,
                      "cannot bind another '" & s.name.s & "' to: " & typeToString(obj))
         return
     if sfSystemModule notin s.owner.flags:
-      localError(n.info, errGenerated,
+      localError(c.config, n.info, errGenerated,
                 "signature for '" & s.name.s & "' must be proc[T: object](x: var T; y: T)")
   else:
     if sfOverriden in s.flags:
-      localError(n.info, errGenerated,
+      localError(c.config, n.info, errGenerated,
                  "'destroy' or 'deepCopy' expected for 'override'")
 
 proc cursorInProcAux(n: PNode): bool =
@@ -1426,7 +1437,7 @@ proc semMethodPrototype(c: PContext; s: PSym; n: PNode) =
           foundObj = true
           x.methods.safeAdd((col,s))
     if not foundObj:
-      message(n.info, warnDeprecated, "generic method not attachable to object type")
+      message(c.config, n.info, warnDeprecated, "generic method not attachable to object type")
   else:
     # why check for the body? bug #2400 has none. Checking for sfForward makes
     # no sense either.
@@ -1434,7 +1445,7 @@ proc semMethodPrototype(c: PContext; s: PSym; n: PNode) =
     if hasObjParam(s):
       methodDef(c.graph, s, fromCache=false)
     else:
-      localError(n.info, errXNeedsParamObjectType, "method")
+      localError(c.config, n.info, "'method' needs a parameter that has an object type")
 
 proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
                 validPragmas: TSpecialWords,
@@ -1442,7 +1453,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
   result = semProcAnnotation(c, n, validPragmas)
   if result != nil: return result
   result = n
-  checkSonsLen(n, bodyPos + 1)
+  checkSonsLen(n, bodyPos + 1, c.config)
   var s: PSym
   var typeIsDetermined = false
   var isAnon = false
@@ -1531,10 +1542,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
       # XXX This needs more checks eventually, for example that external
       # linking names do agree:
       if proto.typ.callConv != s.typ.callConv or proto.typ.flags < s.typ.flags:
-        localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX,
-          "'" & proto.name.s & "' from " & $proto.info)
+        localError(c.config, n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX %
+          ("'" & proto.name.s & "' from " & $proto.info))
     if sfForward notin proto.flags:
-      wrongRedefinition(n.info, proto.name.s)
+      wrongRedefinition(c, n.info, proto.name.s)
     excl(proto.flags, sfForward)
     closeScope(c)         # close scope with wrong parameter symbols
     openScope(c)          # open scope for old (correct) parameter symbols
@@ -1547,32 +1558,32 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     n.sons[genericParamsPos] = proto.ast.sons[genericParamsPos]
     n.sons[paramsPos] = proto.ast.sons[paramsPos]
     n.sons[pragmasPos] = proto.ast.sons[pragmasPos]
-    if n.sons[namePos].kind != nkSym: internalError(n.info, "semProcAux")
+    if n.sons[namePos].kind != nkSym: internalError(c.config, n.info, "semProcAux")
     n.sons[namePos].sym = proto
-    if importantComments() and not isNil(proto.ast.comment):
+    if importantComments(c.config) and not isNil(proto.ast.comment):
       n.comment = proto.ast.comment
     proto.ast = n             # needed for code generation
     popOwner(c)
     pushOwner(c, s)
-  s.options = gOptions
+  s.options = c.config.options
   if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
   if s.name.s[0] in {'.', '('}:
     if s.name.s in [".", ".()", ".="] and {destructor, dotOperators} * c.features == {}:
-      localError(n.info, "the overloaded " & s.name.s &
+      localError(c.config, n.info, "the overloaded " & s.name.s &
         " operator has to be enabled with {.experimental: \"dotOperators\".}")
     elif s.name.s == "()" and callOperator notin c.features:
-      localError(n.info, "the overloaded " & s.name.s &
+      localError(c.config, n.info, "the overloaded " & s.name.s &
         " operator has to be enabled with {.experimental: \"callOperator\".}")
 
   if n.sons[bodyPos].kind != nkEmpty:
     # for DLL generation it is annoying to check for sfImportc!
     if sfBorrow in s.flags:
-      localError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s)
+      localError(c.config, n.sons[bodyPos].info, errImplOfXNotAllowed % s.name.s)
     let usePseudoGenerics = kind in {skMacro, skTemplate}
     # Macros and Templates can have generic parameters, but they are
     # only used for overload resolution (there is no instantiation of
     # the symbol, so we must process the body now)
-    if not usePseudoGenerics and gIdeCmd in {ideSug, ideCon} and not
+    if not usePseudoGenerics and c.config.ideCmd in {ideSug, ideCon} and not
         cursorInProc(n.sons[bodyPos]):
       discard "speed up nimsuggest"
       if s.kind == skMethod: semMethodPrototype(c, s, n)
@@ -1590,7 +1601,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
           let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
           # unfortunately we cannot skip this step when in 'system.compiles'
           # context as it may even be evaluated in 'system.compiles':
-          n.sons[bodyPos] = transformBody(c.module, c.features, semBody, s)
+          n.sons[bodyPos] = transformBody(c.graph, c.module, semBody, s)
       else:
         if s.typ.sons[0] != nil and kind != skIterator:
           addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info))
@@ -1606,7 +1617,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
       popProcCon(c)
   else:
     if s.kind == skMethod: semMethodPrototype(c, s, n)
-    if proto != nil: localError(n.info, errImplOfXexpected, proto.name.s)
+    if proto != nil: localError(c.config, n.info, errImplOfXexpected % proto.name.s)
     if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone:
       incl(s.flags, sfForward)
     elif sfBorrow in s.flags: semBorrow(c, n, s)
@@ -1621,7 +1632,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     result.typ = s.typ
   if isTopLevel(c) and s.kind != skIterator and
       s.typ.callConv == ccClosure:
-    localError(s.info, "'.closure' calling convention for top level routines is invalid")
+    localError(c.config, s.info, "'.closure' calling convention for top level routines is invalid")
 
 proc determineType(c: PContext, s: PSym) =
   if s.typ != nil: return
@@ -1644,9 +1655,9 @@ proc semIterator(c: PContext, n: PNode): PNode =
   var s = result.sons[namePos].sym
   var t = s.typ
   if t.sons[0] == nil and s.typ.callConv != ccClosure:
-    localError(n.info, errXNeedsReturnType, "iterator")
+    localError(c.config, n.info, "iterator needs a return type")
   if isAnon and s.typ.callConv == ccInline:
-    localError(n.info, "inline iterators are not first-class / cannot be assigned to variables")
+    localError(c.config, n.info, "inline iterators are not first-class / cannot be assigned to variables")
   # iterators are either 'inline' or 'closure'; for backwards compatibility,
   # we require first class iterators to be marked with 'closure' explicitly
   # -- at least for 0.9.2.
@@ -1655,7 +1666,7 @@ proc semIterator(c: PContext, n: PNode): PNode =
   else:
     s.typ.callConv = ccInline
   if n.sons[bodyPos].kind == nkEmpty and s.magic == mNone:
-    localError(n.info, errImplOfXexpected, s.name.s)
+    localError(c.config, n.info, errImplOfXexpected % s.name.s)
 
 proc semProc(c: PContext, n: PNode): PNode =
   result = semProcAux(c, n, skProc, procPragmas)
@@ -1664,7 +1675,7 @@ proc semFunc(c: PContext, n: PNode): PNode =
   result = semProcAux(c, n, skFunc, procPragmas)
 
 proc semMethod(c: PContext, n: PNode): PNode =
-  if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method")
+  if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "method")
   result = semProcAux(c, n, skMethod, methodPragmas)
   # macros can transform converters to nothing:
   if namePos >= result.safeLen: return result
@@ -1685,8 +1696,8 @@ proc semMethod(c: PContext, n: PNode): PNode =
       else: disp.ast[resultPos].sym.typ = ret
 
 proc semConverterDef(c: PContext, n: PNode): PNode =
-  if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter")
-  checkSonsLen(n, bodyPos + 1)
+  if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "converter")
+  checkSonsLen(n, bodyPos + 1, c.config)
   result = semProcAux(c, n, skConverter, converterPragmas)
   # macros can transform converters to nothing:
   if namePos >= result.safeLen: return result
@@ -1696,12 +1707,12 @@ proc semConverterDef(c: PContext, n: PNode): PNode =
   if result.kind != nkConverterDef: return
   var s = result.sons[namePos].sym
   var t = s.typ
-  if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "converter")
-  if sonsLen(t) != 2: localError(n.info, errXRequiresOneArgument, "converter")
+  if t.sons[0] == nil: localError(c.config, n.info, errXNeedsReturnType % "converter")
+  if sonsLen(t) != 2: localError(c.config, n.info, "a converter takes exactly one argument")
   addConverter(c, s)
 
 proc semMacroDef(c: PContext, n: PNode): PNode =
-  checkSonsLen(n, bodyPos + 1)
+  checkSonsLen(n, bodyPos + 1, c.config)
   result = semProcAux(c, n, skMacro, macroPragmas)
   # macros can transform macros to nothing:
   if namePos >= result.safeLen: return result
@@ -1716,18 +1727,18 @@ proc semMacroDef(c: PContext, n: PNode): PNode =
     let param = t.n.sons[i].sym
     if param.typ.kind != tyExpr: allUntyped = false
   if allUntyped: incl(s.flags, sfAllUntyped)
-  if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro")
+  if t.sons[0] == nil: localError(c.config, n.info, "macro needs a return type")
   if n.sons[bodyPos].kind == nkEmpty:
-    localError(n.info, errImplOfXexpected, s.name.s)
+    localError(c.config, n.info, errImplOfXexpected % s.name.s)
 
 proc evalInclude(c: PContext, n: PNode): PNode =
   result = newNodeI(nkStmtList, n.info)
   addSon(result, n)
   for i in countup(0, sonsLen(n) - 1):
-    var f = checkModuleName(n.sons[i])
+    var f = checkModuleName(c.config, n.sons[i])
     if f != InvalidFileIDX:
       if containsOrIncl(c.includedFiles, f.int):
-        localError(n.info, errRecursiveDependencyX, f.toFilename)
+        localError(c.config, n.info, errRecursiveDependencyX % f.toFilename)
       else:
         addSon(result, semStmt(c, gIncludeFile(c.graph, c.module, f, c.cache)))
         excl(c.includedFiles, f.int)
@@ -1758,7 +1769,7 @@ proc semStaticStmt(c: PContext, n: PNode): PNode =
   let a = semStmt(c, n.sons[0])
   dec c.inStaticContext
   n.sons[0] = a
-  evalStaticStmt(c.module, c.cache, c.graph.config, a, c.p.owner)
+  evalStaticStmt(c.module, c.cache, c.graph, a, c.p.owner)
   result = newNodeI(nkDiscardStmt, n.info, 1)
   result.sons[0] = emptyNode
 
@@ -1779,7 +1790,7 @@ proc inferConceptStaticParam(c: PContext, inferred, n: PNode) =
   var typ = inferred.typ
   let res = semConstExpr(c, n)
   if not sameType(res.typ, typ.base):
-    localError(n.info,
+    localError(c.config, n.info,
       "cannot infer the concept parameter '%s', due to a type mismatch. " &
       "attempt to equate '%s' and '%s'.",
       [inferred.renderTree, $res.typ, $typ.base])
@@ -1820,7 +1831,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
 
         let verdict = semConstExpr(c, n[i])
         if verdict.intVal == 0:
-          localError(result.info, "concept predicate failed")
+          localError(c.config, result.info, "concept predicate failed")
       of tyUnknown: continue
       else: discard
     if n.sons[i].typ == enforceVoidContext: #or usesResult(n.sons[i]):
@@ -1841,7 +1852,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
         case n.sons[j].kind
         of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkBlockExpr,
             nkBlockStmt, nkState: discard
-        else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
+        else: localError(c.config, n.sons[j].info, "unreachable statement after 'return'")
     else: discard
 
   if result.len == 1 and
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 454dadec0..352bc5c6b 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -26,6 +26,9 @@ discard """
   a way to achieve lexical scoping at compile time.
 """
 
+const
+  errImplOfXNotAllowed = "implementation of '$1' is not allowed"
+
 type
   TSymBinding = enum
     spNone, spGenSym, spInject
@@ -60,7 +63,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
     # (s.kind notin routineKinds or s.magic != mNone):
     # for instance 'nextTry' is both in tables.nim and astalgo.nim ...
     result = newSymNode(s, n.info)
-    markUsed(n.info, s, c.graph.usageSym)
+    markUsed(c.config, n.info, s, c.graph.usageSym)
   else:
     # semantic checking requires a type; ``fitNode`` deals with it
     # appropriately
@@ -91,20 +94,20 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
       else:
         for x in items(sc): toBind.incl(x.sym.id)
     else:
-      illFormedAst(a)
+      illFormedAst(a, c.config)
   result = newNodeI(nkEmpty, n.info)
 
 proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode =
   for i in 0 ..< n.len:
-    toMixin.incl(considerQuotedIdent(n.sons[i]).id)
+    toMixin.incl(considerQuotedIdent(c.config, n.sons[i]).id)
   result = newNodeI(nkEmpty, n.info)
 
-proc replaceIdentBySym(n: var PNode, s: PNode) =
+proc replaceIdentBySym(c: PContext; n: var PNode, s: PNode) =
   case n.kind
-  of nkPostfix: replaceIdentBySym(n.sons[1], s)
-  of nkPragmaExpr: replaceIdentBySym(n.sons[0], s)
+  of nkPostfix: replaceIdentBySym(c, n.sons[1], s)
+  of nkPragmaExpr: replaceIdentBySym(c, n.sons[0], s)
   of nkIdent, nkAccQuoted, nkSym: n = s
-  else: illFormedAst(n)
+  else: illFormedAst(n, c.config)
 
 type
   TemplCtx = object
@@ -129,7 +132,7 @@ proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
         result = newSymNode(s, n.info)
   of nkAccQuoted, nkSym: result = n
   else:
-    illFormedAst(n)
+    illFormedAst(n, c.c.config)
     result = n
 
 proc isTemplParam(c: TemplCtx, n: PNode): bool {.inline.} =
@@ -163,7 +166,7 @@ proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode =
       result.sons[i] = onlyReplaceParams(c, n.sons[i])
 
 proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym =
-  result = newSym(kind, considerQuotedIdent(n), c.owner, n.info)
+  result = newSym(kind, considerQuotedIdent(c.c.config, n), c.owner, n.info)
   incl(result.flags, sfGenSym)
   incl(result.flags, sfShadowed)
 
@@ -184,12 +187,12 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
         n = onlyReplaceParams(c, n)
         return
       else:
-        illFormedAst(x)
+        illFormedAst(x, c.c.config)
     let ident = getIdentNode(c, x)
     if not isTemplParam(c, ident):
       c.toInject.incl(x.ident.id)
     else:
-      replaceIdentBySym(n, ident)
+      replaceIdentBySym(c.c, n, ident)
   else:
     let ident = getIdentNode(c, n)
     if not isTemplParam(c, ident):
@@ -203,17 +206,17 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
       #
       # We need to ensure that both 'a' produce the same gensym'ed symbol.
       # So we need only check the *current* scope.
-      let s = localSearchInScope(c.c, considerQuotedIdent ident)
+      let s = localSearchInScope(c.c, considerQuotedIdent(c.c.config, ident))
       if s != nil and s.owner == c.owner and sfGenSym in s.flags:
         styleCheckUse(n.info, s)
-        replaceIdentBySym(n, newSymNode(s, n.info))
+        replaceIdentBySym(c.c, n, newSymNode(s, n.info))
       else:
         let local = newGenSym(k, ident, c)
         addPrelimDecl(c.c, local)
         styleCheckDef(n.info, local)
-        replaceIdentBySym(n, newSymNode(local, n.info))
+        replaceIdentBySym(c.c, n, newSymNode(local, n.info))
     else:
-      replaceIdentBySym(n, ident)
+      replaceIdentBySym(c.c, n, ident)
 
 proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
   incl(s.flags, sfUsed)
@@ -249,7 +252,7 @@ proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
 
 proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
   result = n
-  checkSonsLen(n, bodyPos + 1)
+  checkSonsLen(n, bodyPos + 1, c.c.config)
   # routines default to 'inject':
   if n.kind notin nkLambdaKinds and symBinding(n.sons[pragmasPos]) == spGenSym:
     let ident = getIdentNode(c, n.sons[namePos])
@@ -281,8 +284,8 @@ proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind; start=0) =
   for i in countup(start, sonsLen(n) - 1):
     var a = n.sons[i]
     if a.kind == nkCommentStmt: continue
-    if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a)
-    checkMinSonsLen(a, 3)
+    if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a, c.c.config)
+    checkMinSonsLen(a, 3, c.c.config)
     var L = sonsLen(a)
     when defined(nimsuggest):
       inc c.c.inTypeContext
@@ -354,7 +357,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
     n.sons[0] = semTemplBody(c, n.sons[0])
     for i in countup(1, sonsLen(n)-1):
       var a = n.sons[i]
-      checkMinSonsLen(a, 1)
+      checkMinSonsLen(a, 1, c.c.config)
       var L = sonsLen(a)
       for j in countup(0, L-2):
         a.sons[j] = semTemplBody(c, a.sons[j])
@@ -371,7 +374,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
     closeScope(c)
     closeScope(c)
   of nkBlockStmt, nkBlockExpr, nkBlockType:
-    checkSonsLen(n, 2)
+    checkSonsLen(n, 2, c.c.config)
     openScope(c)
     if n.sons[0].kind != nkEmpty:
       addLocalDecl(c, n.sons[0], skLabel)
@@ -384,11 +387,11 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
     n.sons[1] = semTemplBody(c, n.sons[1])
     closeScope(c)
   of nkTryStmt:
-    checkMinSonsLen(n, 2)
+    checkMinSonsLen(n, 2, c.c.config)
     n.sons[0] = semTemplBodyScope(c, n.sons[0])
     for i in countup(1, sonsLen(n)-1):
       var a = n.sons[i]
-      checkMinSonsLen(a, 1)
+      checkMinSonsLen(a, 1, c.c.config)
       var L = sonsLen(a)
       openScope(c)
       for j in countup(0, L-2):
@@ -402,15 +405,15 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
   of nkVarSection: semTemplSomeDecl(c, n, skVar)
   of nkLetSection: semTemplSomeDecl(c, n, skLet)
   of nkFormalParams:
-    checkMinSonsLen(n, 1)
+    checkMinSonsLen(n, 1, c.c.config)
     n.sons[0] = semTemplBody(c, n.sons[0])
     semTemplSomeDecl(c, n, skParam, 1)
   of nkConstSection:
     for i in countup(0, sonsLen(n) - 1):
       var a = n.sons[i]
       if a.kind == nkCommentStmt: continue
-      if (a.kind != nkConstDef): illFormedAst(a)
-      checkSonsLen(a, 3)
+      if (a.kind != nkConstDef): illFormedAst(a, c.c.config)
+      checkSonsLen(a, 3, c.c.config)
       addLocalDecl(c, a.sons[0], skConst)
       a.sons[1] = semTemplBody(c, a.sons[1])
       a.sons[2] = semTemplBody(c, a.sons[2])
@@ -418,14 +421,14 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
     for i in countup(0, sonsLen(n) - 1):
       var a = n.sons[i]
       if a.kind == nkCommentStmt: continue
-      if (a.kind != nkTypeDef): illFormedAst(a)
-      checkSonsLen(a, 3)
+      if (a.kind != nkTypeDef): illFormedAst(a, c.c.config)
+      checkSonsLen(a, 3, c.c.config)
       addLocalDecl(c, a.sons[0], skType)
     for i in countup(0, sonsLen(n) - 1):
       var a = n.sons[i]
       if a.kind == nkCommentStmt: continue
-      if (a.kind != nkTypeDef): illFormedAst(a)
-      checkSonsLen(a, 3)
+      if (a.kind != nkTypeDef): illFormedAst(a, c.c.config)
+      checkSonsLen(a, 3, c.c.config)
       if a.sons[1].kind != nkEmpty:
         openScope(c)
         a.sons[1] = semTemplBody(c, a.sons[1])
@@ -468,7 +471,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
     for i in 0 ..< n.len: result.add(n[i])
     result = semTemplBodySons(c, result)
   of nkAsgn, nkFastAsgn:
-    checkSonsLen(n, 2)
+    checkSonsLen(n, 2, c.c.config)
     let a = n.sons[0]
     let b = n.sons[1]
 
@@ -610,9 +613,9 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
   result = n
   if sfCustomPragma in s.flags:
     if n.sons[bodyPos].kind != nkEmpty:
-      localError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s)
+      localError(c.config, n.sons[bodyPos].info, errImplOfXNotAllowed % s.name.s)
   elif n.sons[bodyPos].kind == nkEmpty:
-    localError(n.info, errImplOfXexpected, s.name.s)
+    localError(c.config, n.info, "implementation of '$1' expected" % s.name.s)
   var proto = searchForProc(c, c.currentScope, s)
   if proto == nil:
     addInterfaceOverloadableSymAt(c, c.currentScope, s)
@@ -655,7 +658,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
     if s != nil and s.owner == c.owner and s.kind == skParam:
       result = newParam(c, n, s)
     else:
-      localError(n.info, errInvalidExpression)
+      localError(c.c.config, n.info, "invalid expression")
       result = n
 
   proc stupidStmtListExpr(n: PNode): bool =
@@ -675,7 +678,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
     # we support '(pattern){x}' to bind a subpattern to a parameter 'x';
     # '(pattern){|x}' does the same but the matches will be gathered in 'x'
     if n.len != 2:
-      localError(n.info, errInvalidExpression)
+      localError(c.c.config, n.info, "invalid expression")
     elif n.sons[1].kind == nkIdent:
       n.sons[0] = semPatternBody(c, n.sons[0])
       n.sons[1] = expectParam(c, n.sons[1])
@@ -685,9 +688,9 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
         n.sons[0] = semPatternBody(c, n.sons[0])
         n.sons[1].sons[1] = expectParam(c, n.sons[1].sons[1])
       else:
-        localError(n.info, errInvalidExpression)
+        localError(c.c.config, n.info, "invalid expression")
     else:
-      localError(n.info, errInvalidExpression)
+      localError(c.c.config, n.info, "invalid expression")
   of nkStmtList, nkStmtListExpr:
     if stupidStmtListExpr(n):
       result = semPatternBody(c, n.lastSon)
@@ -759,5 +762,5 @@ proc semPattern(c: PContext, n: PNode): PNode =
     if result.len == 1:
       result = result.sons[0]
     elif result.len == 0:
-      localError(n.info, errInvalidExpression)
+      localError(c.config, n.info, "a pattern cannot be empty")
   closeScope(c)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 537319d66..8b5c26f99 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -10,6 +10,33 @@
 # this module does the semantic checking of type declarations
 # included from sem.nim
 
+const
+  errStringLiteralExpected = "string literal expected"
+  errIntLiteralExpected = "integer literal expected"
+  errWrongNumberOfVariables = "wrong number of variables"
+  errInvalidOrderInEnumX = "invalid order in enum '$1'"
+  errOrdinalTypeExpected = "ordinal type expected"
+  errSetTooBig = "set is too large"
+  errBaseTypeMustBeOrdinal = "base type of a set must be an ordinal"
+  errInheritanceOnlyWithNonFinalObjects = "inheritance only works with non-final objects"
+  errXExpectsOneTypeParam = "'$1' expects one type parameter"
+  errArrayExpectsTwoTypeParams = "array expects two type parameters"
+  errInvalidVisibilityX = "invalid visibility: '$1'"
+  errInitHereNotAllowed = "initialization not allowed here"
+  errXCannotBeAssignedTo = "'$1' cannot be assigned to"
+  errIteratorNotAllowed = "iterators can only be defined at the module's top level"
+  errXNeedsReturnType = "$1 needs a return type"
+  errNoReturnTypeDeclared = "no return type declared"
+  errTIsNotAConcreteType = "'$1' is not a concrete type"
+  errTypeExpected = "type expected"
+  errXOnlyAtModuleScope = "'$1' is only allowed at top level"
+  errDuplicateCaseLabel = "duplicate case label"
+  errMacroBodyDependsOnGenericTypes = "the macro body cannot be compiled, " &
+    "because the parameter '$1' has a generic type"
+  errIllegalRecursionInTypeX = "illegal recursion in type '$1'"
+  errNoGenericParamsAllowedForX = "no generic parameters allowed for $1"
+  errInOutFlagNotExtern = "the '$1' modifier can be used only with imported types"
+
 proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
   if prev == nil:
     result = newTypeS(kind, c)
@@ -34,11 +61,11 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
   base = nil
   result = newOrPrevType(tyEnum, prev, c)
   result.n = newNodeI(nkEnumTy, n.info)
-  checkMinSonsLen(n, 1)
+  checkMinSonsLen(n, 1, c.config)
   if n.sons[0].kind != nkEmpty:
     base = semTypeNode(c, n.sons[0].sons[0], nil)
     if base.kind != tyEnum:
-      localError(n.sons[0].info, errInheritanceOnlyWithEnums)
+      localError(c.config, n.sons[0].info, "inheritance only works with an enum")
     counter = lastOrd(base) + 1
   rawAddSon(result, base)
   let isPure = result.sym != nil and sfPure in result.sym.flags
@@ -58,9 +85,9 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
           if skipTypes(strVal.typ, abstractInst).kind in {tyString, tyCString}:
             x = getOrdValue(v.sons[0]) # first tuple part is the ordinal
           else:
-            localError(strVal.info, errStringLiteralExpected)
+            localError(c.config, strVal.info, errStringLiteralExpected)
         else:
-          localError(v.info, errWrongNumberOfVariables)
+          localError(c.config, v.info, errWrongNumberOfVariables)
       of tyString, tyCString:
         strVal = v
         x = counter
@@ -69,7 +96,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
       if i != 1:
         if x != counter: incl(result.flags, tfEnumHasHoles)
         if x < counter:
-          localError(n.sons[i].info, errInvalidOrderInEnumX, e.name.s)
+          localError(c.config, n.sons[i].info, errInvalidOrderInEnumX % e.name.s)
           x = counter
       e.ast = strVal # might be nil
       counter = x
@@ -78,7 +105,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
     of nkIdent, nkAccQuoted:
       e = newSymS(skEnumField, n.sons[i], c)
     else:
-      illFormedAst(n[i])
+      illFormedAst(n[i], c.config)
     e.typ = result
     e.position = int(counter)
     if e.position == 0: hasNull = true
@@ -87,12 +114,13 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
       incl(e.flags, sfExported)
       if not isPure: strTableAdd(c.module.tab, e)
     addSon(result.n, newSymNode(e))
+    let conf = c.config
     styleCheckDef(e)
     if sfGenSym notin e.flags:
       if not isPure: addDecl(c, e)
       else: importPureEnumField(c, e)
     if isPure and strTableIncl(symbols, e):
-      wrongRedefinition(e.info, e.name.s)
+      wrongRedefinition(c, e.info, e.name.s)
     inc(counter)
   if not hasNull: incl(result.flags, tfNeedsInit)
 
@@ -104,11 +132,11 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType =
     if base.kind in {tyGenericInst, tyAlias, tySink}: base = lastSon(base)
     if base.kind != tyGenericParam:
       if not isOrdinalType(base):
-        localError(n.info, errOrdinalTypeExpected)
+        localError(c.config, n.info, errOrdinalTypeExpected)
       elif lengthOrd(base) > MaxSetElements:
-        localError(n.info, errSetTooBig)
+        localError(c.config, n.info, errSetTooBig)
   else:
-    localError(n.info, errXExpectsOneTypeParam, "set")
+    localError(c.config, n.info, errXExpectsOneTypeParam % "set")
     addSonSkipIntLit(result, errorType(c))
 
 proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
@@ -117,10 +145,10 @@ proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
   if sonsLen(n) == 2:
     var base = semTypeNode(c, n.sons[1], nil)
     if base.kind == tyVoid:
-      localError(n.info, errTIsNotAConcreteType, typeToString(base))
+      localError(c.config, n.info, errTIsNotAConcreteType % typeToString(base))
     addSonSkipIntLit(result, base)
   else:
-    localError(n.info, errXExpectsOneTypeParam, kindStr)
+    localError(c.config, n.info, errXExpectsOneTypeParam % kindStr)
     addSonSkipIntLit(result, errorType(c))
 
 proc semVarargs(c: PContext, n: PNode, prev: PType): PType =
@@ -129,9 +157,9 @@ proc semVarargs(c: PContext, n: PNode, prev: PType): PType =
     var base = semTypeNode(c, n.sons[1], nil)
     addSonSkipIntLit(result, base)
     if sonsLen(n) == 3:
-      result.n = newIdentNode(considerQuotedIdent(n.sons[2]), n.sons[2].info)
+      result.n = newIdentNode(considerQuotedIdent(c.config, n.sons[2]), n.sons[2].info)
   else:
-    localError(n.info, errXExpectsOneTypeParam, "varargs")
+    localError(c.config, n.info, errXExpectsOneTypeParam % "varargs")
     addSonSkipIntLit(result, errorType(c))
 
 proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
@@ -140,7 +168,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
   else:
     let isCall = int ord(n.kind in nkCallKinds+{nkBracketExpr})
     let n = if n[0].kind == nkBracket: n[0] else: n
-    checkMinSonsLen(n, 1)
+    checkMinSonsLen(n, 1, c.config)
     var t = semTypeNode(c, n.lastSon, nil)
     if t.kind == tyTypeDesc and tfUnresolved notin t.flags:
       t = t.base
@@ -155,7 +183,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
         let region = semTypeNode(c, ni, nil)
         if region.skipTypes({tyGenericInst, tyAlias, tySink}).kind notin {
               tyError, tyObject}:
-          message n[i].info, errGenerated, "region needs to be an object type"
+          message c.config, n[i].info, errGenerated, "region needs to be an object type"
         addSonSkipIntLit(result, region)
     addSonSkipIntLit(result, t)
     if tfPartial in result.flags:
@@ -167,7 +195,7 @@ proc semVarType(c: PContext, n: PNode, prev: PType): PType =
     result = newOrPrevType(tyVar, prev, c)
     var base = semTypeNode(c, n.sons[0], nil).skipTypes({tyTypeDesc})
     if base.kind == tyVar:
-      localError(n.info, errVarVarTypeNotAllowed)
+      localError(c.config, n.info, "type 'var var' is not allowed")
       base = base.sons[0]
     addSonSkipIntLit(result, base)
   else:
@@ -181,7 +209,7 @@ proc semDistinct(c: PContext, n: PNode, prev: PType): PType =
 
 proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
   assert isRange(n)
-  checkSonsLen(n, 3)
+  checkSonsLen(n, 3, c.config)
   result = newOrPrevType(tyRange, prev, c)
   result.n = newNodeI(nkRange, n.info)
   # always create a 'valid' range type, but overwrite it later
@@ -189,7 +217,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
   addSonSkipIntLit(result, errorType(c))
 
   if (n[1].kind == nkEmpty) or (n[2].kind == nkEmpty):
-    localError(n.info, errRangeIsEmpty)
+    localError(c.config, n.info, "range is empty")
 
   var range: array[2, PNode]
   range[0] = semExprWithType(c, n[1], {efDetermineType})
@@ -204,11 +232,11 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
 
   if not hasUnknownTypes:
     if not sameType(rangeT[0].skipTypes({tyRange}), rangeT[1].skipTypes({tyRange})):
-      localError(n.info, errPureTypeMismatch)
+      localError(c.config, n.info, "type mismatch")
     elif not rangeT[0].isOrdinalType:
-      localError(n.info, errOrdinalTypeExpected)
+      localError(c.config, n.info, "ordinal type expected")
     elif enumHasHoles(rangeT[0]):
-      localError(n.info, errEnumXHasHoles, rangeT[0].sym.name.s)
+      localError(c.config, n.info, "enum '$1' has holes" % typeToString(rangeT[0]))
 
   for i in 0..1:
     if hasGenericArguments(range[i]):
@@ -218,7 +246,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
       result.n.addSon semConstExpr(c, range[i])
 
   if weakLeValue(result.n[0], result.n[1]) == impNo:
-    localError(n.info, errRangeIsEmpty)
+    localError(c.config, n.info, "range is empty")
 
   result[0] = rangeT[0]
 
@@ -239,13 +267,13 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
           n.sons[1].floatVal < 0.0:
         incl(result.flags, tfNeedsInit)
     else:
-      if n[1].kind == nkInfix and considerQuotedIdent(n[1][0]).s == "..<":
-        localError(n[0].info, "range types need to be constructed with '..', '..<' is not supported")
+      if n[1].kind == nkInfix and considerQuotedIdent(c.config, n[1][0]).s == "..<":
+        localError(c.config, n[0].info, "range types need to be constructed with '..', '..<' is not supported")
       else:
-        localError(n.sons[0].info, errRangeExpected)
+        localError(c.config, n.sons[0].info, "expected range")
       result = newOrPrevType(tyError, prev, c)
   else:
-    localError(n.info, errXExpectsOneTypeParam, "range")
+    localError(c.config, n.info, errXExpectsOneTypeParam % "range")
     result = newOrPrevType(tyError, prev, c)
 
 proc semArrayIndex(c: PContext, n: PNode): PType =
@@ -257,7 +285,7 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
       result = makeRangeWithStaticExpr(c, e.typ.n)
     elif e.kind in {nkIntLit..nkUInt64Lit}:
       if e.intVal < 0:
-        localError(n[1].info,
+        localError(c.config, n[1].info,
           "Array length can't be negative, but was " & $e.intVal)
       result = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
     elif e.kind == nkSym and e.typ.kind == tyStatic:
@@ -265,12 +293,12 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
         return semArrayIndex(c, e.sym.ast)
       if not isOrdinalType(e.typ.lastSon):
         let info = if n.safeLen > 1: n[1].info else: n.info
-        localError(info, errOrdinalTypeExpected)
+        localError(c.config, info, errOrdinalTypeExpected)
       result = makeRangeWithStaticExpr(c, e)
       if c.inGenericContext > 0: result.flags.incl tfUnresolved
     elif e.kind in nkCallKinds and hasGenericArguments(e):
       if not isOrdinalType(e.typ):
-        localError(n[1].info, errOrdinalTypeExpected)
+        localError(c.config, n[1].info, errOrdinalTypeExpected)
       # This is an int returning call, depending on an
       # yet unknown generic param (see tgenericshardcases).
       # We are going to construct a range type that will be
@@ -286,7 +314,7 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
                              x.typ.skipTypes({tyTypeDesc}))
       else:
         result = x.typ.skipTypes({tyTypeDesc})
-        #localError(n[1].info, errConstExprExpected)
+        #localError(c.config, n[1].info, errConstExprExpected)
 
 proc semArray(c: PContext, n: PNode, prev: PType): PType =
   var base: PType
@@ -299,9 +327,9 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
       if indxB.skipTypes({tyRange}).kind in {tyUInt, tyUInt64}:
         discard
       elif not isOrdinalType(indxB):
-        localError(n.sons[1].info, errOrdinalTypeExpected)
+        localError(c.config, n.sons[1].info, errOrdinalTypeExpected)
       elif enumHasHoles(indxB):
-        localError(n.sons[1].info, errEnumXHasHoles,
+        localError(c.config, n.sons[1].info, "enum '$1' has holes" %
                    typeToString(indxB.skipTypes({tyRange})))
     base = semTypeNode(c, n.sons[2], nil)
     # ensure we only construct a tyArray when there was no error (bug #3048):
@@ -311,7 +339,7 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
     rawAddSonNoPropagationOfTypeFlags(result, indx)
     addSonSkipIntLit(result, base)
   else:
-    localError(n.info, errArrayExpectsTwoTypeParams)
+    localError(c.config, n.info, errArrayExpectsTwoTypeParams)
     result = newOrPrevType(tyError, prev, c)
 
 proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
@@ -320,10 +348,10 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
     var base = semTypeNode(c, n.sons[1], nil)
     if base.kind != tyGenericParam:
       if not isOrdinalType(base):
-        localError(n.sons[1].info, errOrdinalTypeExpected)
+        localError(c.config, n.sons[1].info, errOrdinalTypeExpected)
     addSonSkipIntLit(result, base)
   else:
-    localError(n.info, errXExpectsOneTypeParam, "ordinal")
+    localError(c.config, n.info, errXExpectsOneTypeParam % "ordinal")
     result = newOrPrevType(tyError, prev, c)
 
 proc semTypeIdent(c: PContext, n: PNode): PSym =
@@ -334,7 +362,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
     if result.isNil:
       result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
     if result != nil:
-      markUsed(n.info, result, c.graph.usageSym)
+      markUsed(c.config, n.info, result, c.graph.usageSym)
       styleCheckUse(n.info, result)
       if result.kind == skParam and result.typ.kind == tyTypeDesc:
         # This is a typedesc param. is it already bound?
@@ -345,7 +373,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
           if bound != nil: return bound
           return result
         if result.typ.sym == nil:
-          localError(n.info, errTypeExpected)
+          localError(c.config, n.info, errTypeExpected)
           return errorSym(c, n)
         result = result.typ.sym.copySym
         result.typ = copyType(result.typ, result.typ.owner, true)
@@ -359,7 +387,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
           result.typ.flags.excl tfWildcard
           return
         else:
-          localError(n.info, errTypeExpected)
+          localError(c.config, n.info, errTypeExpected)
           return errorSym(c, n)
 
       if result.kind != skType:
@@ -370,7 +398,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
           amb = nextOverloadIter(ov, c, n)
         if amb != nil: result = amb
         else:
-          if result.kind != skError: localError(n.info, errTypeExpected)
+          if result.kind != skError: localError(c.config, n.info, errTypeExpected)
           return errorSym(c, n)
       if result.typ.kind != tyGenericParam:
         # XXX get rid of this hack!
@@ -385,12 +413,12 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
         n.info = oldInfo
         n.typ = result.typ
     else:
-      localError(n.info, errIdentifierExpected)
+      localError(c.config, n.info, "identifier expected")
       result = errorSym(c, n)
 
 proc semAnonTuple(c: PContext, n: PNode, prev: PType): PType =
   if sonsLen(n) == 0:
-    localError(n.info, errTypeExpected)
+    localError(c.config, n.info, errTypeExpected)
   result = newOrPrevType(tyTuple, prev, c)
   for it in n:
     addSonSkipIntLit(result, semTypeNode(c, it, nil))
@@ -403,27 +431,27 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
   var counter = 0
   for i in countup(ord(n.kind == nkBracketExpr), sonsLen(n) - 1):
     var a = n.sons[i]
-    if (a.kind != nkIdentDefs): illFormedAst(a)
-    checkMinSonsLen(a, 3)
+    if (a.kind != nkIdentDefs): illFormedAst(a, c.config)
+    checkMinSonsLen(a, 3, c.config)
     var length = sonsLen(a)
     if a.sons[length - 2].kind != nkEmpty:
       typ = semTypeNode(c, a.sons[length - 2], nil)
     else:
-      localError(a.info, errTypeExpected)
+      localError(c.config, a.info, errTypeExpected)
       typ = errorType(c)
     if a.sons[length - 1].kind != nkEmpty:
-      localError(a.sons[length - 1].info, errInitHereNotAllowed)
+      localError(c.config, a.sons[length - 1].info, errInitHereNotAllowed)
     for j in countup(0, length - 3):
       var field = newSymG(skField, a.sons[j], c)
       field.typ = typ
       field.position = counter
       inc(counter)
       if containsOrIncl(check, field.name.id):
-        localError(a.sons[j].info, errAttemptToRedefine, field.name.s)
+        localError(c.config, a.sons[j].info, "attempt to redefine: '" & field.name.s & "'")
       else:
         addSon(result.n, newSymNode(field))
         addSonSkipIntLit(result, typ)
-      if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, field)
+      if c.config.cmd == cmdPretty: styleCheckDef(a.sons[j].info, field)
   if result.n.len == 0: result.n = nil
 
 proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
@@ -434,23 +462,23 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
       # for gensym'ed identifiers the identifier may already have been
       # transformed to a symbol and we need to use that here:
       result = newSymG(kind, n.sons[1], c)
-      var v = considerQuotedIdent(n.sons[0])
+      var v = considerQuotedIdent(c.config, n.sons[0])
       if sfExported in allowed and v.id == ord(wStar):
         incl(result.flags, sfExported)
       else:
         if not (sfExported in allowed):
-          localError(n.sons[0].info, errXOnlyAtModuleScope, "export")
+          localError(c.config, n.sons[0].info, errXOnlyAtModuleScope % "export")
         else:
-          localError(n.sons[0].info, errInvalidVisibilityX, renderTree(n[0]))
+          localError(c.config, n.sons[0].info, errInvalidVisibilityX % renderTree(n[0]))
     else:
-      illFormedAst(n)
+      illFormedAst(n, c.config)
   else:
     result = newSymG(kind, n, c)
 
 proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
                         allowed: TSymFlags): PSym =
   if n.kind == nkPragmaExpr:
-    checkSonsLen(n, 2)
+    checkSonsLen(n, 2, c.config)
     result = semIdentVis(c, kind, n.sons[0], allowed)
     case kind
     of skType:
@@ -463,7 +491,7 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
     else: discard
   else:
     result = semIdentVis(c, kind, n, allowed)
-  if gCmd == cmdPretty: styleCheckDef(n.info, result)
+  if c.config.cmd == cmdPretty: styleCheckDef(n.info, result)
 
 proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
   let ex = t[branchIndex][currentEx].skipConv
@@ -471,10 +499,10 @@ proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
     for j in countup(0, sonsLen(t.sons[i]) - 2):
       if i == branchIndex and j == currentEx: break
       if overlap(t.sons[i].sons[j].skipConv, ex):
-        localError(ex.info, errDuplicateCaseLabel)
+        localError(c.config, ex.info, errDuplicateCaseLabel)
 
 proc semBranchRange(c: PContext, t, a, b: PNode, covered: var BiggestInt): PNode =
-  checkMinSonsLen(t, 1)
+  checkMinSonsLen(t, 1, c.config)
   let ac = semConstExpr(c, a)
   let bc = semConstExpr(c, b)
   let at = fitNode(c, t.sons[0].typ, ac, ac.info).skipConvTakeType
@@ -483,21 +511,21 @@ proc semBranchRange(c: PContext, t, a, b: PNode, covered: var BiggestInt): PNode
   result = newNodeI(nkRange, a.info)
   result.add(at)
   result.add(bt)
-  if emptyRange(ac, bc): localError(b.info, errRangeIsEmpty)
+  if emptyRange(ac, bc): localError(c.config, b.info, "range is empty")
   else: covered = covered + getOrdValue(bc) - getOrdValue(ac) + 1
 
 proc semCaseBranchRange(c: PContext, t, b: PNode,
                         covered: var BiggestInt): PNode =
-  checkSonsLen(b, 3)
+  checkSonsLen(b, 3, c.config)
   result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
 
 proc semCaseBranchSetElem(c: PContext, t, b: PNode,
                           covered: var BiggestInt): PNode =
   if isRange(b):
-    checkSonsLen(b, 3)
+    checkSonsLen(b, 3, c.config)
     result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
   elif b.kind == nkRange:
-    checkSonsLen(b, 2)
+    checkSonsLen(b, 2, c.config)
     result = semBranchRange(c, t, b.sons[0], b.sons[1], covered)
   else:
     result = fitNode(c, t.sons[0].typ, b, b.info)
@@ -520,7 +548,7 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
         delSon(branch, 0)
         return
       elif r.kind notin {nkCurly, nkBracket} or len(r) == 0:
-        checkMinSonsLen(t, 1)
+        checkMinSonsLen(t, 1, c.config)
         branch.sons[i] = skipConv(fitNode(c, t.sons[0].typ, r, r.info))
         inc(covered)
       else:
@@ -546,37 +574,37 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
 proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
                    father: PNode, rectype: PType) =
   var a = copyNode(n)
-  checkMinSonsLen(n, 2)
+  checkMinSonsLen(n, 2, c.config)
   semRecordNodeAux(c, n.sons[0], check, pos, a, rectype)
   if a.sons[0].kind != nkSym:
-    internalError("semRecordCase: discriminant is no symbol")
+    internalError(c.config, "semRecordCase: discriminant is no symbol")
     return
   incl(a.sons[0].sym.flags, sfDiscriminant)
   var covered: BiggestInt = 0
   var typ = skipTypes(a.sons[0].typ, abstractVar-{tyTypeDesc})
   if not isOrdinalType(typ):
-    localError(n.info, errSelectorMustBeOrdinal)
+    localError(c.config, n.info, "selector must be of an ordinal type")
   elif firstOrd(typ) != 0:
-    localError(n.info, errGenerated, "low(" & $a.sons[0].sym.name.s &
+    localError(c.config, n.info, "low(" & $a.sons[0].sym.name.s &
                                      ") must be 0 for discriminant")
   elif lengthOrd(typ) > 0x00007FFF:
-    localError(n.info, errLenXinvalid, a.sons[0].sym.name.s)
+    localError(c.config, n.info, "len($1) must be less than 32768" % a.sons[0].sym.name.s)
   var chckCovered = true
   for i in countup(1, sonsLen(n) - 1):
     var b = copyTree(n.sons[i])
     addSon(a, b)
     case n.sons[i].kind
     of nkOfBranch:
-      checkMinSonsLen(b, 2)
+      checkMinSonsLen(b, 2, c.config)
       semCaseBranch(c, a, b, i, covered)
     of nkElse:
       chckCovered = false
-      checkSonsLen(b, 1)
-    else: illFormedAst(n)
+      checkSonsLen(b, 1, c.config)
+    else: illFormedAst(n, c.config)
     delSon(b, sonsLen(b) - 1)
     semRecordNodeAux(c, lastSon(n.sons[i]), check, pos, b, rectype)
-  if chckCovered and (covered != lengthOrd(a.sons[0].typ)):
-    localError(a.info, errNotAllCasesCovered)
+  if chckCovered and covered != lengthOrd(a.sons[0].typ):
+    localError(c.config, a.info, "not all cases are covered")
   addSon(father, a)
 
 proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
@@ -587,22 +615,22 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
     var branch: PNode = nil   # the branch to take
     for i in countup(0, sonsLen(n) - 1):
       var it = n.sons[i]
-      if it == nil: illFormedAst(n)
+      if it == nil: illFormedAst(n, c.config)
       var idx = 1
       case it.kind
       of nkElifBranch:
-        checkSonsLen(it, 2)
+        checkSonsLen(it, 2, c.config)
         if c.inGenericContext == 0:
           var e = semConstBoolExpr(c, it.sons[0])
-          if e.kind != nkIntLit: internalError(e.info, "semRecordNodeAux")
+          if e.kind != nkIntLit: internalError(c.config, e.info, "semRecordNodeAux")
           elif e.intVal != 0 and branch == nil: branch = it.sons[1]
         else:
           it.sons[0] = forceBool(c, semExprWithType(c, it.sons[0]))
       of nkElse:
-        checkSonsLen(it, 1)
+        checkSonsLen(it, 1, c.config)
         if branch == nil: branch = it.sons[0]
         idx = 0
-      else: illFormedAst(n)
+      else: illFormedAst(n, c.config)
       if c.inGenericContext > 0:
         # use a new check intset here for each branch:
         var newCheck: IntSet
@@ -626,16 +654,16 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
       semRecordNodeAux(c, n.sons[i], check, pos, a, rectype)
     if a != father: addSon(father, a)
   of nkIdentDefs:
-    checkMinSonsLen(n, 3)
+    checkMinSonsLen(n, 3, c.config)
     var length = sonsLen(n)
     var a: PNode
     if father.kind != nkRecList and length>=4: a = newNodeI(nkRecList, n.info)
     else: a = ast.emptyNode
     if n.sons[length-1].kind != nkEmpty:
-      localError(n.sons[length-1].info, errInitHereNotAllowed)
+      localError(c.config, n.sons[length-1].info, errInitHereNotAllowed)
     var typ: PType
     if n.sons[length-2].kind == nkEmpty:
-      localError(n.info, errTypeExpected)
+      localError(c.config, n.info, errTypeExpected)
       typ = errorType(c)
     else:
       typ = semTypeNode(c, n.sons[length-2], nil)
@@ -644,7 +672,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
                      else: rectype.sym
     for i in countup(0, sonsLen(n)-3):
       var f = semIdentWithPragma(c, skField, n.sons[i], {sfExported})
-      suggestSym(n.sons[i].info, f, c.graph.usageSym)
+      suggestSym(c.config, n.sons[i].info, f, c.graph.usageSym)
       f.typ = typ
       f.position = pos
       if fieldOwner != nil and
@@ -654,7 +682,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
         f.flags = f.flags + ({sfImportc, sfExportc} * fieldOwner.flags)
       inc(pos)
       if containsOrIncl(check, f.name.id):
-        localError(n.sons[i].info, errAttemptToRedefine, f.name.s)
+        localError(c.config, n.sons[i].info, "attempt to redefine: '" & f.name.s & "'")
       if a.kind == nkEmpty: addSon(father, newSymNode(f))
       else: addSon(a, newSymNode(f))
       styleCheckDef(f)
@@ -664,29 +692,29 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
     # inherited from generic/partial specialized parent second check.
     # There is no branch validity check here
     if containsOrIncl(check, n.sym.name.id):
-      localError(n.info, errAttemptToRedefine, n.sym.name.s)
+      localError(c.config, n.info, "attempt to redefine: '" & n.sym.name.s & "'")
     addSon(father, n)
   of nkEmpty: discard
-  else: illFormedAst(n)
+  else: illFormedAst(n, c.config)
 
 proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
                            n: PNode) =
   case n.kind
   of nkRecCase:
-    if (n.sons[0].kind != nkSym): internalError(n.info, "addInheritedFieldsAux")
+    if (n.sons[0].kind != nkSym): internalError(c.config, n.info, "addInheritedFieldsAux")
     addInheritedFieldsAux(c, check, pos, n.sons[0])
     for i in countup(1, sonsLen(n) - 1):
       case n.sons[i].kind
       of nkOfBranch, nkElse:
         addInheritedFieldsAux(c, check, pos, lastSon(n.sons[i]))
-      else: internalError(n.info, "addInheritedFieldsAux(record case branch)")
+      else: internalError(c.config, n.info, "addInheritedFieldsAux(record case branch)")
   of nkRecList:
     for i in countup(0, sonsLen(n) - 1):
       addInheritedFieldsAux(c, check, pos, n.sons[i])
   of nkSym:
     incl(check, n.sym.name.id)
     inc(pos)
-  else: internalError(n.info, "addInheritedFieldsAux()")
+  else: internalError(c.config, n.info, "addInheritedFieldsAux()")
 
 proc skipGenericInvocation(t: PType): PType {.inline.} =
   result = t
@@ -709,12 +737,12 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
   var pos = 0
   var base, realBase: PType = nil
   # n.sons[0] contains the pragmas (if any). We process these later...
-  checkSonsLen(n, 3)
+  checkSonsLen(n, 3, c.config)
   if n.sons[1].kind != nkEmpty:
     realBase = semTypeNode(c, n.sons[1].sons[0], nil)
     base = skipTypesOrNil(realBase, skipPtrs)
     if base.isNil:
-      localError(n.info, errIllegalRecursionInTypeX, "object")
+      localError(c.config, n.info, "cannot inherit from a type that is not an object type")
     else:
       var concreteBase = skipGenericInvocation(base)
       if concreteBase.kind in {tyObject, tyGenericParam,
@@ -727,11 +755,11 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
           addInheritedFields(c, check, pos, concreteBase)
       else:
         if concreteBase.kind != tyError:
-          localError(n.sons[1].info, "inheritance only works with non-final objects; " &
+          localError(c.config, n.sons[1].info, "inheritance only works with non-final objects; " &
              "to enable inheritance write '" & typeToString(realBase) & " of RootObj'")
         base = nil
         realBase = nil
-  if n.kind != nkObjectTy: internalError(n.info, "semObjectNode")
+  if n.kind != nkObjectTy: internalError(c.config, n.info, "semObjectNode")
   result = newOrPrevType(tyObject, prev, c)
   rawAddSon(result, realBase)
   if result.n.isNil:
@@ -769,8 +797,7 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
       addDecl(c, param)
     else:
       # within a macro, every param has the type NimNode!
-      let nn = if getCompilerProc("NimNode") != nil: getSysSym"NimNode"
-               else: getSysSym"PNimrodNode"
+      let nn = getSysSym(c.graph, param.info, "NimNode")
       var a = copySym(param)
       a.typ = nn.typ
       addDecl(c, a)
@@ -780,7 +807,7 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
 let typedescId = getIdent"typedesc"
 
 template shouldHaveMeta(t) =
-  internalAssert tfHasMeta in t.flags
+  internalAssert c.config, tfHasMeta in t.flags
   # result.lastSon.flags.incl tfHasMeta
 
 proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
@@ -838,7 +865,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
     if tfUnresolved in paramType.flags: return # already lifted
     let base = paramType.base.maybeLift
     if base.isMetaType and procKind == skMacro:
-      localError(info, errMacroBodyDependsOnGenericTypes, paramName)
+      localError(c.config, info, errMacroBodyDependsOnGenericTypes % paramName)
     result = addImplicitGeneric(c.newTypeWithSons(tyStatic, @[base]))
     result.flags.incl({tfHasStatic, tfUnresolved})
 
@@ -870,7 +897,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
     else:
       for i in 0 ..< paramType.len:
         if paramType.sons[i] == paramType:
-          globalError(info, errIllegalRecursionInTypeX, typeToString(paramType))
+          globalError(c.config, info, errIllegalRecursionInTypeX % typeToString(paramType))
         var lifted = liftingWalk(paramType.sons[i])
         if lifted != nil:
           paramType.sons[i] = lifted
@@ -939,7 +966,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
     result = addImplicitGeneric(copyType(paramType, getCurrOwner(c), false))
 
   of tyGenericParam:
-    markUsed(info, paramType.sym, c.graph.usageSym)
+    markUsed(c.config, info, paramType.sym, c.graph.usageSym)
     styleCheckUse(info, paramType.sym)
     if tfWildcard in paramType.flags:
       paramType.flags.excl tfWildcard
@@ -952,7 +979,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
 proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType =
   if n.kind == nkCurlyExpr:
     result = semTypeNode(c, n.sons[0], nil)
-    constraint = semNodeKindConstraints(n)
+    constraint = semNodeKindConstraints(n, c.config)
   else:
     result = semTypeNode(c, n, nil)
 
@@ -971,7 +998,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
   # for historical reasons (code grows) this is invoked for parameter
   # lists too and then 'isType' is false.
   var cl: IntSet
-  checkMinSonsLen(n, 1)
+  checkMinSonsLen(n, 1, c.config)
   result = newProcType(c, n.info, prev)
   if genericParams != nil and sonsLen(genericParams) == 0:
     cl = initIntSet()
@@ -985,8 +1012,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       # skip this parameter here. It'll then be re-generated in another LL
       # pass over this instantiation:
       if a.kind == nkSym and sfFromGeneric in a.sym.flags: continue
-      illFormedAst(a)
-    checkMinSonsLen(a, 3)
+      illFormedAst(a, c.config)
+    checkMinSonsLen(a, 3, c.config)
     var
       typ: PType = nil
       def: PNode = nil
@@ -1009,7 +1036,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
         if not containsGenericType(typ):
           def = fitNode(c, typ, def, def.info)
     if not hasType and not hasDefault:
-      if isType: localError(a.info, "':' expected")
+      if isType: localError(c.config, a.info, "':' expected")
       if kind in {skTemplate, skMacro}:
         typ = newTypeS(tyExpr, c)
     elif skipTypes(typ, {tyGenericInst, tyAlias, tySink}).kind == tyVoid:
@@ -1020,7 +1047,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
         let param = strTableGet(c.signatures, arg.name)
         if param != nil: typ = param.typ
         else:
-          localError(a.info, "typeless parameters are obsolete")
+          localError(c.config, a.info, "typeless parameters are obsolete")
           typ = errorType(c)
       let lifted = liftParamType(c, kind, genericParams, typ,
                                  arg.name.s, arg.info)
@@ -1031,11 +1058,11 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       inc(counter)
       if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
       if containsOrIncl(check, arg.name.id):
-        localError(a.sons[j].info, errAttemptToRedefine, arg.name.s)
+        localError(c.config, a.sons[j].info, "attempt to redefine: '" & arg.name.s & "'")
       addSon(result.n, newSymNode(arg))
       rawAddSon(result, finalType)
       addParamOrResult(c, arg, kind)
-      if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, arg)
+      if c.config.cmd == cmdPretty: styleCheckDef(a.sons[j].info, arg)
 
   var r: PType
   if n.sons[0].kind != nkEmpty:
@@ -1085,7 +1112,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
         n.sym.typ.flags.excl tfWildcard
 
 proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
-  checkMinSonsLen(n, 1)
+  checkMinSonsLen(n, 1, c.config)
   var length = sonsLen(n)
   for i in countup(0, length - 2):
     n.sons[i] = semStmt(c, n.sons[i])
@@ -1098,7 +1125,7 @@ proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
 
 proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
   inc(c.p.nestedBlockCounter)
-  checkSonsLen(n, 2)
+  checkSonsLen(n, 2, c.config)
   openScope(c)
   if n.sons[0].kind notin {nkEmpty, nkSym}:
     addDecl(c, newSymS(skLabel, n.sons[0], c))
@@ -1120,20 +1147,20 @@ proc semObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType) =
     realBase = t.sons[0]
     base = skipTypesOrNil(realBase, skipPtrs)
   if base.isNil:
-    localError(n.info, errIllegalRecursionInTypeX, "object")
+    localError(c.config, n.info, errIllegalRecursionInTypeX % "object")
   else:
     let concreteBase = skipGenericInvocation(base)
     if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
       addInheritedFields(c, check, pos, concreteBase)
     else:
       if concreteBase.kind != tyError:
-        localError(n.info, errInheritanceOnlyWithNonFinalObjects)
+        localError(c.config, n.info, errInheritanceOnlyWithNonFinalObjects)
   var newf = newNodeI(nkRecList, n.info)
   semRecordNodeAux(c, t.n, check, pos, newf, t)
 
 proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
   if s.typ == nil:
-    localError(n.info, "cannot instantiate the '$1' $2" %
+    localError(c.config, n.info, "cannot instantiate the '$1' $2" %
                        [s.name.s, ($s.kind).substr(2).toLowerAscii])
     return newOrPrevType(tyError, prev, c)
 
@@ -1146,7 +1173,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
 
   template addToResult(typ) =
     if typ.isNil:
-      internalAssert false
+      internalAssert c.config, false
       rawAddSon(result, typ)
     else: addSonSkipIntLit(result, typ)
 
@@ -1158,7 +1185,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
   elif t.kind != tyGenericBody:
     # we likely got code of the form TypeA[TypeB] where TypeA is
     # not generic.
-    localError(n.info, errNoGenericParamsAllowedForX, s.name.s)
+    localError(c.config, n.info, errNoGenericParamsAllowedForX % s.name.s)
     return newOrPrevType(tyError, prev, c)
   else:
     var m = newCandidate(c, t)
@@ -1169,7 +1196,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
       let err = "cannot instantiate " & typeToString(t) & "\n" &
                 "got: <" & describeArgs(c, n) & ">\n" &
                 "but expected: <" & describeArgs(c, t.n, 0) & ">"
-      localError(n.info, errGenerated, err)
+      localError(c.config, n.info, errGenerated, err)
       return newOrPrevType(tyError, prev, c)
 
     var isConcrete = true
@@ -1187,7 +1214,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
     if isConcrete:
       if s.ast == nil and s.typ.kind != tyCompositeTypeClass:
         # XXX: What kind of error is this? is it still relevant?
-        localError(n.info, errCannotInstantiateX, s.name.s)
+        localError(c.config, n.info, errCannotInstantiateX % s.name.s)
         result = newOrPrevType(tyError, prev, c)
       else:
         result = instGenericContainer(c, n.info, result,
@@ -1197,7 +1224,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
   # generic/partial specialized parent
   let tx = result.skipTypes(abstractPtrs, 50)
   if tx.isNil:
-    localError(n.info, "invalid recursion in type '$1'" % typeToString(result[0]))
+    localError(c.config, n.info, "invalid recursion in type '$1'" % typeToString(result[0]))
     return errorType(c)
   if tx != result and tx.kind == tyObject and tx.sons[0] != nil:
     semObjectTypeForInheritedGenericInst(c, n, tx)
@@ -1226,7 +1253,7 @@ proc semTypeExpr(c: PContext, n: PNode; prev: PType): PType =
         let alias = maybeAliasType(c, result, prev)
         if alias != nil: result = alias
   else:
-    localError(n.info, errTypeExpected, n.renderTree)
+    localError(c.config, n.info, "expected type, but got: " & n.renderTree)
     result = errorType(c)
 
 proc freshType(res, prev: PType): PType {.inline.} =
@@ -1277,7 +1304,7 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
       dummyName = param
       dummyType = candidateTypeSlot
 
-    internalAssert dummyName.kind == nkIdent
+    internalAssert c.config, dummyName.kind == nkIdent
     var dummyParam = newSym(if modifier == tyTypeDesc: skType else: skVar,
                             dummyName.ident, owner, param.info)
     dummyParam.typ = dummyType
@@ -1289,7 +1316,7 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
 
 proc semProcTypeWithScope(c: PContext, n: PNode,
                         prev: PType, kind: TSymKind): PType =
-  checkSonsLen(n, 2)
+  checkSonsLen(n, 2, c.config)
   openScope(c)
   result = semProcTypeNode(c, n.sons[0], nil, prev, kind, isType=true)
   # start with 'ccClosure', but of course pragmas can overwrite this:
@@ -1299,7 +1326,7 @@ proc semProcTypeWithScope(c: PContext, n: PNode,
   s.typ = result
   if n.sons[1].kind != nkEmpty and n.sons[1].len > 0:
     pragma(c, s, n.sons[1], procTypePragmas)
-    when useEffectSystem: setEffectsForProcType(result, n.sons[1])
+    when useEffectSystem: setEffectsForProcType(c.graph, result, n.sons[1])
   closeScope(c)
 
 proc maybeAliasType(c: PContext; typeExpr, prev: PType): PType =
@@ -1320,19 +1347,19 @@ proc symFromExpectedTypeNode(c: PContext, n: PNode): PSym =
   if n.kind == nkType:
     result = symFromType(n.typ, n.info)
   else:
-    localError(n.info, errTypeExpected)
+    localError(c.config, n.info, errTypeExpected)
     result = errorSym(c, n)
 
 proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   result = nil
   inc c.inTypeContext
 
-  if gCmd == cmdIdeTools: suggestExpr(c, n)
+  if c.config.cmd == cmdIdeTools: suggestExpr(c, n)
   case n.kind
   of nkEmpty: discard
   of nkTypeOfExpr:
     # for ``type(countup(1,3))``, see ``tests/ttoseq``.
-    checkSonsLen(n, 1)
+    checkSonsLen(n, 1, c.config)
     let typExpr = semExprWithType(c, n.sons[0], {efInTypeof})
     fixupTypeOf(c, prev, typExpr)
     result = typExpr.typ
@@ -1362,21 +1389,21 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
           result = freshType(result, prev)
           result.flags.excl(tfNotNil)
       else:
-        localError(n.info, errGenerated, "invalid type")
+        localError(c.config, n.info, errGenerated, "invalid type")
     elif n[0].kind notin nkIdentKinds:
       result = semTypeExpr(c, n, prev)
     else:
-      let op = considerQuotedIdent(n.sons[0])
+      let op = considerQuotedIdent(c.config, n.sons[0])
       if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
-        checkSonsLen(n, 3)
+        checkSonsLen(n, 3, c.config)
         var
           t1 = semTypeNode(c, n.sons[1], nil)
           t2 = semTypeNode(c, n.sons[2], nil)
         if t1 == nil:
-          localError(n.sons[1].info, errTypeExpected)
+          localError(c.config, n.sons[1].info, errTypeExpected)
           result = newOrPrevType(tyError, prev, c)
         elif t2 == nil:
-          localError(n.sons[2].info, errTypeExpected)
+          localError(c.config, n.sons[2].info, errTypeExpected)
           result = newOrPrevType(tyError, prev, c)
         else:
           result = if op.id == ord(wAnd): makeAndType(c, t1, t2)
@@ -1390,20 +1417,20 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
             result = freshType(result, prev)
             result.flags.incl(tfNotNil)
             if notnil notin c.features:
-              localError(n.info, "enable the 'not nil' annotation with {.experimental: \"notnil\".}")
+              localError(c.config, n.info, "enable the 'not nil' annotation with {.experimental: \"notnil\".}")
           else:
-            localError(n.info, errGenerated, "invalid type")
+            localError(c.config, n.info, errGenerated, "invalid type")
         of 2:
           let negated = semTypeNode(c, n.sons[1], prev)
           result = makeNotType(c, negated)
         else:
-          localError(n.info, errGenerated, "invalid type")
+          localError(c.config, n.info, errGenerated, "invalid type")
       elif op.id == ord(wPtr):
         result = semAnyRef(c, n, tyPtr, prev)
       elif op.id == ord(wRef):
         result = semAnyRef(c, n, tyRef, prev)
       elif op.id == ord(wType):
-        checkSonsLen(n, 2)
+        checkSonsLen(n, 2, c.config)
         let typExpr = semExprWithType(c, n.sons[1], {efInTypeof})
         fixupTypeOf(c, prev, typExpr)
         result = typExpr.typ
@@ -1417,7 +1444,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
     if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType
     result = semTypeNode(c, whenResult, prev)
   of nkBracketExpr:
-    checkMinSonsLen(n, 2)
+    checkMinSonsLen(n, 2, c.config)
     var head = n.sons[0]
     var s = if head.kind notin nkCallKinds: semTypeIdent(c, head)
             else: symFromExpectedTypeNode(c, semExpr(c, head))
@@ -1444,7 +1471,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
       result = newOrPrevType(tyVar, prev, c)
       var base = semTypeNode(c, n.sons[1], nil)
       if base.kind in {tyVar, tyLent}:
-        localError(n.info, errVarVarTypeNotAllowed)
+        localError(c.config, n.info, "type 'var var' is not allowed")
         base = base.sons[0]
       addSonSkipIntLit(result, base)
     of mRef: result = semAnyRef(c, n, tyRef, prev)
@@ -1454,13 +1481,13 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   of nkDotExpr:
     let typeExpr = semExpr(c, n)
     if typeExpr.typ.isNil:
-      localError(n.info, "object constructor needs an object type;" &
+      localError(c.config, n.info, "object constructor needs an object type;" &
           " for named arguments use '=' instead of ':'")
       result = errorType(c)
     elif typeExpr.typ.kind == tyFromExpr:
       result = typeExpr.typ
     elif typeExpr.typ.kind != tyTypeDesc:
-      localError(n.info, errTypeExpected)
+      localError(c.config, n.info, errTypeExpected)
       result = errorType(c)
     else:
       result = typeExpr.typ.base
@@ -1476,10 +1503,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   of nkIdent, nkAccQuoted:
     var s = semTypeIdent(c, n)
     if s.typ == nil:
-      if s.kind != skError: localError(n.info, errTypeExpected)
+      if s.kind != skError: localError(c.config, n.info, errTypeExpected)
       result = newOrPrevType(tyError, prev, c)
     elif s.kind == skParam and s.typ.kind == tyTypeDesc:
-      internalAssert s.typ.base.kind != tyNone and prev == nil
+      internalAssert c.config, s.typ.base.kind != tyNone and prev == nil
       result = s.typ.base
     elif prev == nil:
       result = s.typ
@@ -1506,10 +1533,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
       else:
         assignType(prev, t)
         result = prev
-      markUsed(n.info, n.sym, c.graph.usageSym)
+      markUsed(c.config, n.info, n.sym, c.graph.usageSym)
       styleCheckUse(n.info, n.sym)
     else:
-      if s.kind != skError: localError(n.info, errTypeExpected)
+      if s.kind != skError: localError(c.config, n.info, errTypeExpected)
       result = newOrPrevType(tyError, prev, c)
   of nkObjectTy: result = semObjectNode(c, n, prev)
   of nkTupleTy: result = semTuple(c, n, prev)
@@ -1547,7 +1574,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   of nkStmtListType: result = semStmtListType(c, n, prev)
   of nkBlockType: result = semBlockType(c, n, prev)
   else:
-    localError(n.info, errTypeExpected)
+    localError(c.config, n.info, errTypeExpected)
     result = newOrPrevType(tyError, prev, c)
   n.typ = result
   dec c.inTypeContext
@@ -1600,10 +1627,10 @@ proc processMagicType(c: PContext, m: PSym) =
   of mChar: setMagicType(m, tyChar, 1)
   of mString:
     setMagicType(m, tyString, ptrSize)
-    rawAddSon(m.typ, getSysType(tyChar))
+    rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar))
   of mCstring:
     setMagicType(m, tyCString, ptrSize)
-    rawAddSon(m.typ, getSysType(tyChar))
+    rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar))
   of mPointer: setMagicType(m, tyPointer, ptrSize)
   of mEmptySet:
     setMagicType(m, tySet, 1)
@@ -1649,8 +1676,8 @@ proc processMagicType(c: PContext, m: PSym) =
     case m.name.s
     of "lent": setMagicType(m, tyLent, ptrSize)
     of "sink": setMagicType(m, tySink, 0)
-    else: localError(m.info, errTypeExpected)
-  else: localError(m.info, errTypeExpected)
+    else: localError(c.config, m.info, errTypeExpected)
+  else: localError(c.config, m.info, errTypeExpected)
 
 proc semGenericConstraints(c: PContext, x: PType): PType =
   result = newTypeWithSons(c, tyGenericParam, @[x])
@@ -1658,11 +1685,11 @@ proc semGenericConstraints(c: PContext, x: PType): PType =
 proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
   result = copyNode(n)
   if n.kind != nkGenericParams:
-    illFormedAst(n)
+    illFormedAst(n, c.config)
     return
   for i in countup(0, sonsLen(n)-1):
     var a = n.sons[i]
-    if a.kind != nkIdentDefs: illFormedAst(n)
+    if a.kind != nkIdentDefs: illFormedAst(n, c.config)
     let L = a.len
     var def = a[^1]
     let constraint = a[^2]
@@ -1708,7 +1735,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
       if paramName.safeLen == 2:
         if not nimEnableCovariance or paramName[0].ident.s == "in":
           if father == nil or sfImportc notin father.sym.flags:
-            localError(paramName.info, errInOutFlagNotExtern, paramName[0].ident.s)
+            localError(c.config, paramName.info, errInOutFlagNotExtern % $paramName[0])
         covarianceFlag = if paramName[0].ident.s == "in": tfContravariant
                          else: tfCovariant
         if father != nil: father.flags.incl tfCovariant
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index c97c1186e..61d92bb19 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -14,21 +14,21 @@ import ast, astalgo, msgs, types, magicsys, semdata, renderer, options
 const
   tfInstClearedFlags = {tfHasMeta, tfUnresolved}
 
-proc checkPartialConstructedType(info: TLineInfo, t: PType) =
+proc checkPartialConstructedType(conf: ConfigRef; info: TLineInfo, t: PType) =
   if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
-    localError(info, errInvalidPragmaX, "acyclic")
+    localError(conf, info, "invalid pragma: acyclic")
   elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}:
-    localError(info, errVarVarTypeNotAllowed)
+    localError(conf, info, "type 'var var' is not allowed")
 
-proc checkConstructedType*(info: TLineInfo, typ: PType) =
+proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) =
   var t = typ.skipTypes({tyDistinct})
   if t.kind in tyTypeClasses: discard
   elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
-    localError(info, errInvalidPragmaX, "acyclic")
+    localError(conf, info, "invalid pragma: acyclic")
   elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}:
-    localError(info, errVarVarTypeNotAllowed)
+    localError(conf, info, "type 'var var' is not allowed")
   elif computeSize(t) == szIllegalRecursion:
-    localError(info, errIllegalRecursionInTypeX, typeToString(t))
+    localError(conf, info,  "illegal recursion in type '" & typeToString(t) & "'")
   when false:
     if t.kind == tyObject and t.sons[0] != nil:
       if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
@@ -36,9 +36,8 @@ proc checkConstructedType*(info: TLineInfo, typ: PType) =
 
 proc searchInstTypes*(key: PType): PType =
   let genericTyp = key.sons[0]
-  internalAssert genericTyp.kind == tyGenericBody and
-                 key.sons[0] == genericTyp and
-                 genericTyp.sym != nil
+  if not (genericTyp.kind == tyGenericBody and
+      key.sons[0] == genericTyp and genericTyp.sym != nil): return
 
   if genericTyp.sym.typeInstCache == nil:
     return
@@ -195,19 +194,19 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode =
     var branch: PNode = nil              # the branch to take
     for i in countup(0, sonsLen(n) - 1):
       var it = n.sons[i]
-      if it == nil: illFormedAst(n)
+      if it == nil: illFormedAst(n, cl.c.config)
       case it.kind
       of nkElifBranch:
-        checkSonsLen(it, 2)
+        checkSonsLen(it, 2, cl.c.config)
         var cond = prepareNode(cl, it.sons[0])
         var e = cl.c.semConstExpr(cl.c, cond)
         if e.kind != nkIntLit:
-          internalError(e.info, "ReplaceTypeVarsN: when condition not a bool")
+          internalError(cl.c.config, e.info, "ReplaceTypeVarsN: when condition not a bool")
         if e.intVal != 0 and branch == nil: branch = it.sons[1]
       of nkElse:
-        checkSonsLen(it, 1)
+        checkSonsLen(it, 1, cl.c.config)
         if branch == nil: branch = it.sons[0]
-      else: illFormedAst(n)
+      else: illFormedAst(n, cl.c.config)
     if branch != nil:
       result = replaceTypeVarsN(cl, branch)
     else:
@@ -244,14 +243,14 @@ proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
   result = cl.typeMap.lookup(t)
   if result == nil:
     if cl.allowMetaTypes or tfRetType in t.flags: return
-    localError(t.sym.info, errCannotInstantiateX, typeToString(t))
+    localError(cl.c.config, t.sym.info, "cannot instantiate: '" & typeToString(t) & "'")
     result = errorType(cl.c)
     # In order to prevent endless recursions, we must remember
     # this bad lookup and replace it with errorType everywhere.
     # These code paths are only active in "nim check"
     cl.typeMap.put(t, result)
   elif result.kind == tyGenericParam and not cl.allowMetaTypes:
-    internalError(cl.info, "substitution with generic parameter")
+    internalError(cl.c.config, cl.info, "substitution with generic parameter")
 
 proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
   # XXX: relying on allowMetaTypes is a kludge
@@ -278,7 +277,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
   # is difficult to handle:
   const eqFlags = eqTypeFlags + {tfGcSafe}
   var body = t.sons[0]
-  if body.kind != tyGenericBody: internalError(cl.info, "no generic body")
+  if body.kind != tyGenericBody: internalError(cl.c.config, cl.info, "no generic body")
   var header: PType = t
   # search for some instantiation here:
   if cl.allowMetaTypes:
@@ -351,7 +350,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
   # handleGenericInvocation will handle the alias-to-alias-to-alias case
   if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
   rawAddSon(result, newbody)
-  checkPartialConstructedType(cl.info, newbody)
+  checkPartialConstructedType(cl.c.config, cl.info, newbody)
   let dc = newbody.deepCopy
   if cl.allowMetaTypes == false:
     if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
@@ -417,7 +416,7 @@ proc propagateFieldFlags(t: PType, n: PNode) =
   # The type must be fully instantiated!
   if n.isNil:
     return
-  internalAssert n.kind != nkRecWhen
+  #internalAssert n.kind != nkRecWhen
   case n.kind
   of nkSym:
     propagateToOwner(t, n.sym.typ)
@@ -454,7 +453,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
       result.kind = tyUserTypeClassInst
 
   of tyGenericBody:
-    localError(cl.info, errCannotInstantiateX, typeToString(t))
+    localError(cl.c.config, cl.info, "cannot instantiate: '" & typeToString(t) & "'")
     result = errorType(cl.c)
     #result = replaceTypeVarsT(cl, lastSon(t))
 
@@ -533,7 +532,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
       case result.kind
       of tyArray:
         let idx = result.sons[0]
-        internalAssert idx.kind != tyStatic
+        internalAssert cl.c.config, idx.kind != tyStatic
 
       of tyObject, tyTuple:
         propagateFieldFlags(result, result.n)
diff --git a/compiler/service.nim b/compiler/service.nim
index 6ec9b9046..f1a988ae5 100644
--- a/compiler/service.nim
+++ b/compiler/service.nim
@@ -11,7 +11,7 @@
 
 import
   times, commands, options, msgs, nimconf,
-  extccomp, strutils, os, platform, parseopt, idents
+  extccomp, strutils, os, platform, parseopt, idents, configuration
 
 when useCaas:
   import net
@@ -42,17 +42,17 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
     of cmdArgument:
       if processArgument(pass, p, argsCount, config): break
   if pass == passCmd2:
-    if optRun notin gGlobalOptions and config.arguments.len > 0 and options.command.normalize != "run":
-      rawMessage(errArgsNeedRunOption, [])
+    if optRun notin config.globalOptions and config.arguments.len > 0 and config.command.normalize != "run":
+      rawMessage(config, errGenerated, errArgsNeedRunOption)
 
 proc serve*(cache: IdentCache; action: proc (cache: IdentCache){.nimcall.}; config: ConfigRef) =
   template execute(cmd) =
     curCaasCmd = cmd
     processCmdLine(passCmd2, cmd, config)
     action(cache)
-    gErrorCounter = 0
+    config.errorCounter = 0
 
-  let typ = getConfigVar("server.type")
+  let typ = getConfigVar(config, "server.type")
   case typ
   of "stdin":
     while true:
@@ -65,9 +65,9 @@ proc serve*(cache: IdentCache; action: proc (cache: IdentCache){.nimcall.}; conf
   of "tcp", "":
     when useCaas:
       var server = newSocket()
-      let p = getConfigVar("server.port")
+      let p = getConfigVar(config, "server.port")
       let port = if p.len > 0: parseInt(p).Port else: 6000.Port
-      server.bindAddr(port, getConfigVar("server.address"))
+      server.bindAddr(port, getConfigVar(config, "server.address"))
       var inp = "".TaintedString
       server.listen()
       var stdoutSocket = newSocket()
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 55d83d990..41cac2a4a 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -99,7 +99,7 @@ type
 const
   isNilConversion = isConvertible # maybe 'isIntConv' fits better?
 
-proc markUsed*(info: TLineInfo, s: PSym; usageSym: var PSym)
+proc markUsed*(conf: ConfigRef; info: TLineInfo, s: PSym; usageSym: var PSym)
 
 template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone
 
@@ -152,13 +152,13 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
     for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1):
       var formalTypeParam = typeParams.sons[i-1].typ
       var bound = binding[i].typ
-      internalAssert bound != nil
-      if formalTypeParam.kind == tyTypeDesc:
-        if bound.kind != tyTypeDesc:
-          bound = makeTypeDesc(ctx, bound)
-      else:
-        bound = bound.skipTypes({tyTypeDesc})
-      put(c, formalTypeParam, bound)
+      if bound != nil:
+        if formalTypeParam.kind == tyTypeDesc:
+          if bound.kind != tyTypeDesc:
+            bound = makeTypeDesc(ctx, bound)
+        else:
+          bound = bound.skipTypes({tyTypeDesc})
+        put(c, formalTypeParam, bound)
 
 proc newCandidate*(ctx: PContext, callee: PSym,
                    binding: PNode, calleeScope = -1): TCandidate =
@@ -362,8 +362,8 @@ proc concreteType(c: TCandidate, t: PType): PType =
         # proc sort[T](cmp: proc(a, b: T): int = cmp)
       if result.kind != tyGenericParam: break
   of tyGenericInvocation:
-    internalError("cannot resolve type: " & typeToString(t))
     result = t
+    doAssert(false, "cannot resolve type: " & typeToString(t))
   else:
     result = t                # Note: empty is valid here
 
@@ -519,8 +519,8 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
     if f.n != nil and a.n != nil:
       for i in countup(0, sonsLen(f.n) - 1):
         # check field names:
-        if f.n.sons[i].kind != nkSym: internalError(f.n.info, "recordRel")
-        elif a.n.sons[i].kind != nkSym: internalError(a.n.info, "recordRel")
+        if f.n.sons[i].kind != nkSym: return isNone
+        elif a.n.sons[i].kind != nkSym: return isNone
         else:
           var x = f.n.sons[i].sym
           var y = a.n.sons[i].sym
@@ -612,7 +612,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
     if tfNoSideEffect in f.flags and tfNoSideEffect notin a.flags:
       return isNone
     elif tfThread in f.flags and a.flags * {tfThread, tfNoSideEffect} == {} and
-        optThreadAnalysis in gGlobalOptions:
+        optThreadAnalysis in c.c.config.globalOptions:
       # noSideEffect implies ``tfThread``!
       return isNone
     elif f.flags * {tfIterator} != a.flags * {tfIterator}:
@@ -661,7 +661,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
     matchedConceptContext.prev = prevMatchedConcept
     matchedConceptContext.depth = prevMatchedConcept.depth + 1
     if prevMatchedConcept.depth > 4:
-      localError(body.info, $body & " too nested for type matching")
+      localError(m.c.graph.config, body.info, $body & " too nested for type matching")
       return nil
 
   openScope(c)
@@ -686,7 +686,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
       if alreadyBound != nil: typ = alreadyBound
 
       template paramSym(kind): untyped =
-        newSym(kind, typeParamName, typeClass.sym, typeClass.sym.info)
+        newSym(kind, typeParamName, typeClass.sym, typeClass.sym.info, {})
 
       block addTypeParam:
         for prev in typeParams:
@@ -760,19 +760,20 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
 
   result.n = checkedBody
 
-proc shouldSkipDistinct(rules: PNode, callIdent: PIdent): bool =
+proc shouldSkipDistinct(m: TCandidate; rules: PNode, callIdent: PIdent): bool =
+  # XXX This is bad as 'considerQuotedIdent' can produce an error!
   if rules.kind == nkWith:
     for r in rules:
-      if r.considerQuotedIdent == callIdent: return true
+      if considerQuotedIdent(m.c.graph.config, r) == callIdent: return true
     return false
   else:
     for r in rules:
-      if r.considerQuotedIdent == callIdent: return false
+      if considerQuotedIdent(m.c.graph.config, r) == callIdent: return false
     return true
 
-proc maybeSkipDistinct(t: PType, callee: PSym): PType =
+proc maybeSkipDistinct(m: TCandidate; t: PType, callee: PSym): PType =
   if t != nil and t.kind == tyDistinct and t.n != nil and
-     shouldSkipDistinct(t.n, callee.name):
+     shouldSkipDistinct(m, t.n, callee.name):
     result = t.base
   else:
     result = t
@@ -868,11 +869,11 @@ proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool =
 
   return false
 
-proc failureToInferStaticParam(n: PNode) =
+proc failureToInferStaticParam(conf: ConfigRef; n: PNode) =
   let staticParam = n.findUnresolvedStatic
   let name = if staticParam != nil: staticParam.sym.name.s
              else: "unknown"
-  localError(n.info, errCannotInferStaticParam, name)
+  localError(conf, n.info, "cannot infer the value of the static param '" & name & "'")
 
 proc inferStaticsInRange(c: var TCandidate,
                          inferred, concrete: PType): TTypeRelation =
@@ -886,7 +887,7 @@ proc inferStaticsInRange(c: var TCandidate,
     if inferStaticParam(c, exp, rhs):
       return isGeneric
     else:
-      failureToInferStaticParam exp
+      failureToInferStaticParam(c.c.graph.config, exp)
 
   if lowerBound.kind == nkIntLit:
     if upperBound.kind == nkIntLit:
@@ -999,7 +1000,8 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
         of tyStatic:
           candidate = computedType
         else:
-          localError(f.n.info, errTypeExpected)
+          # XXX What is this non-sense? Error reporting in signature matching?
+          discard "localError(f.n.info, errTypeExpected)"
       else:
         discard
 
@@ -1013,7 +1015,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
   template doBind: bool = trDontBind notin flags
 
   # var and static arguments match regular modifier-free types
-  var a = aOrig.skipTypes({tyStatic, tyVar, tyLent}).maybeSkipDistinct(c.calleeSym)
+  var a = maybeSkipDistinct(c, aOrig.skipTypes({tyStatic, tyVar, tyLent}), c.calleeSym)
   # XXX: Theoretically, maybeSkipDistinct could be called before we even
   # start the param matching process. This could be done in `prepareOperand`
   # for example, but unfortunately `prepareOperand` is not called in certain
@@ -1442,7 +1444,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
           (sonsLen(x) - 1 == sonsLen(f)):
       for i in countup(1, sonsLen(f) - 1):
         if x.sons[i].kind == tyGenericParam:
-          internalError("wrong instantiated type!")
+          internalError(c.c.graph.config, "wrong instantiated type!")
         elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype:
           # Workaround for regression #4589
           if f.sons[i].kind != tyTypeDesc: return
@@ -1474,7 +1476,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
           if x == nil:
             discard "maybe fine (for eg. a==tyNil)"
           elif x.kind in {tyGenericInvocation, tyGenericParam}:
-            internalError("wrong instantiated type!")
+            internalError(c.c.graph.config, "wrong instantiated type!")
           else:
             put(c, f.sons[i], x)
 
@@ -1597,7 +1599,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
           if f.sonsLen == 0:
             result = isGeneric
           else:
-            internalAssert a.sons != nil and a.sons.len > 0
+            internalAssert c.c.graph.config, a.sons != nil and a.sons.len > 0
             c.typedescMatched = true
             var aa = a
             while aa.kind in {tyTypeDesc, tyGenericParam} and aa.len > 0:
@@ -1739,13 +1741,13 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
         if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n):
           result = isNone
     else:
-      localError(f.n.info, errTypeExpected)
+      localError(c.c.graph.config, f.n.info, "type expected")
       result = isNone
 
   of tyNone:
     if a.kind == tyNone: result = isEqual
   else:
-    internalError " unknown type kind " & $f.kind
+    internalError c.c.graph.config, " unknown type kind " & $f.kind
 
 proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
   var m: TCandidate
@@ -1758,7 +1760,7 @@ proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate,
   if result == nil:
     result = generateTypeInstance(c, m.bindings, arg, f)
   if result == nil:
-    internalError(arg.info, "getInstantiatedType")
+    internalError(c.graph.config, arg.info, "getInstantiatedType")
     result = errorType(c)
 
 proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
@@ -1771,7 +1773,7 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
       result.typ = errorType(c)
   else:
     result.typ = f
-  if result.typ == nil: internalError(arg.info, "implicitConv")
+  if result.typ == nil: internalError(c.graph.config, arg.info, "implicitConv")
   addSon(result, ast.emptyNode)
   addSon(result, arg)
 
@@ -1792,7 +1794,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
       dest = generateTypeInstance(c, m.bindings, arg, dest)
     let fdest = typeRel(m, f, dest)
     if fdest in {isEqual, isGeneric}:
-      markUsed(arg.info, c.converters[i], c.graph.usageSym)
+      markUsed(c.config, arg.info, c.converters[i], c.graph.usageSym)
       var s = newSymNode(c.converters[i])
       s.typ = c.converters[i].typ
       s.info = arg.info
@@ -2069,7 +2071,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
       result = nil
     elif y.state == csMatch and cmpCandidates(x, y) == 0:
       if x.state != csMatch:
-        internalError(arg.info, "x.state is not csMatch")
+        internalError(m.c.graph.config, arg.info, "x.state is not csMatch")
       # ambiguous: more than one symbol fits!
       # See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match
       # anyway:
@@ -2077,12 +2079,11 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
       else: result = nil
     else:
       # only one valid interpretation found:
-      markUsed(arg.info, arg.sons[best].sym, m.c.graph.usageSym)
+      markUsed(m.c.config, arg.info, arg.sons[best].sym, m.c.graph.usageSym)
       styleCheckUse(arg.info, arg.sons[best].sym)
       result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
                                   argOrig)
 
-
 proc setSon(father: PNode, at: int, son: PNode) =
   let oldLen = father.len
   if oldLen <= at:
@@ -2118,10 +2119,10 @@ proc prepareOperand(c: PContext; a: PNode): PNode =
     result = a
     considerGenSyms(c, result)
 
-proc prepareNamedParam(a: PNode) =
+proc prepareNamedParam(a: PNode; conf: ConfigRef) =
   if a.sons[0].kind != nkIdent:
     var info = a.sons[0].info
-    a.sons[0] = newIdentNode(considerQuotedIdent(a.sons[0]), info)
+    a.sons[0] = newIdentNode(considerQuotedIdent(conf, a.sons[0]), info)
 
 proc arrayConstr(c: PContext, n: PNode): PType =
   result = newTypeS(tyArray, c)
@@ -2186,9 +2187,9 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
     elif n.sons[a].kind == nkExprEqExpr:
       # named param
       # check if m.callee has such a param:
-      prepareNamedParam(n.sons[a])
+      prepareNamedParam(n.sons[a], c.config)
       if n.sons[a].sons[0].kind != nkIdent:
-        localError(n.sons[a].info, errNamedParamHasToBeIdent)
+        localError(c.config, n.sons[a].info, "named parameter has to be an identifier")
         m.state = csNoMatch
         return
       formal = getSymFromList(m.callee.n, n.sons[a].sons[0].ident, 1)
@@ -2231,8 +2232,9 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           # we have no formal here to snoop at:
           n.sons[a] = prepareOperand(c, n.sons[a])
           if skipTypes(n.sons[a].typ, abstractVar-{tyTypeDesc}).kind==tyString:
-            addSon(m.call, implicitConv(nkHiddenStdConv, getSysType(tyCString),
-                                        copyTree(n.sons[a]), m, c))
+            addSon(m.call, implicitConv(nkHiddenStdConv,
+                  getSysType(c.graph, n.sons[a].info, tyCString),
+                  copyTree(n.sons[a]), m, c))
           else:
             addSon(m.call, copyTree(n.sons[a]))
         elif formal != nil and formal.typ.kind == tyVarargs:
@@ -2255,7 +2257,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           return
       else:
         if m.callee.n.sons[f].kind != nkSym:
-          internalError(n.sons[a].info, "matches")
+          internalError(c.config, n.sons[a].info, "matches")
           return
         formal = m.callee.n.sons[f].sym
         if containsOrIncl(marker, formal.position) and container.isNil:
@@ -2363,7 +2365,7 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
   var m: TCandidate
   initCandidate(c, m, dc.typ)
   if col >= dc.typ.len:
-    localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
+    localError(c.config, info, "cannot instantiate: '" & dc.name.s & "'")
     return nil
   var f = dc.typ.sons[col]
 
@@ -2372,7 +2374,7 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
   else:
     if f.kind == tyVar: f = f.lastSon
   if typeRel(m, f, t) == isNone:
-    localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
+    localError(c.config, info, "cannot instantiate: '" & dc.name.s & "'")
   else:
     result = c.semGenerateInstance(c, dc, m.bindings, info)
     if op == attachedDeepCopy:
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index 555ec9867..23aecfa71 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -32,7 +32,7 @@
 
 # included from sigmatch.nim
 
-import algorithm, prefixmatches
+import algorithm, prefixmatches, configuration
 from wordrecg import wDeprecated
 
 when defined(nimsuggest):
@@ -106,7 +106,7 @@ proc cmpSuggestions(a, b: Suggest): int =
   # independent of hashing order:
   result = cmp(a.name.s, b.name.s)
 
-proc symToSuggest(s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo;
+proc symToSuggest(conf: ConfigRef; s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo;
                   quality: range[0..100]; prefix: PrefixMatch;
                   inTypeContext: bool; scope: int): Suggest =
   new(result)
@@ -125,7 +125,7 @@ proc symToSuggest(s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo;
       if u.fileIndex == info.fileIndex: inc c
     result.localUsages = c
   result.symkind = s.kind
-  if optIdeTerse notin gGlobalOptions:
+  if optIdeTerse notin conf.globalOptions:
     result.qualifiedPath = @[]
     if not isLocal and s.kind != skModule:
       let ow = s.owner
@@ -192,8 +192,8 @@ proc suggestResult(s: Suggest) =
   else:
     suggestWriteln($s)
 
-proc produceOutput(a: var Suggestions) =
-  if gIdeCmd in {ideSug, ideCon}:
+proc produceOutput(a: var Suggestions; conf: ConfigRef) =
+  if conf.ideCmd in {ideSug, ideCon}:
     a.sort cmpSuggestions
   when defined(debug):
     # debug code
@@ -237,7 +237,7 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} =
 proc suggestField(c: PContext, s: PSym; f: PNode; info: TLineInfo; outputs: var Suggestions) =
   var pm: PrefixMatch
   if filterSym(s, f, pm) and fieldVisible(c, s):
-    outputs.add(symToSuggest(s, isLocal=true, ideSug, info, 100, pm, c.inTypeContext > 0, 0))
+    outputs.add(symToSuggest(c.config, s, isLocal=true, ideSug, info, 100, pm, c.inTypeContext > 0, 0))
 
 proc getQuality(s: PSym): range[0..100] =
   if s.typ != nil and s.typ.len > 1:
@@ -256,7 +256,7 @@ template wholeSymTab(cond, section: untyped) =
       let it {.inject.} = item
       var pm {.inject.}: PrefixMatch
       if cond:
-        outputs.add(symToSuggest(it, isLocal = isLocal, section, info, getQuality(it),
+        outputs.add(symToSuggest(c.config, it, isLocal = isLocal, section, info, getQuality(it),
                                  pm, c.inTypeContext > 0, scopeN))
 
 proc suggestSymList(c: PContext, list, f: PNode; info: TLineInfo, outputs: var Suggestions) =
@@ -330,7 +330,7 @@ proc suggestEverything(c: PContext, n, f: PNode, outputs: var Suggestions) =
     for it in items(scope.symbols):
       var pm: PrefixMatch
       if filterSym(it, f, pm):
-        outputs.add(symToSuggest(it, isLocal = isLocal, ideSug, n.info, 0, pm,
+        outputs.add(symToSuggest(c.config, it, isLocal = isLocal, ideSug, n.info, 0, pm,
                                  c.inTypeContext > 0, scopeN))
     #if scope == c.topLevelScope and f.isNil: break
 
@@ -342,18 +342,18 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions)
   when defined(nimsuggest):
     if n.kind == nkSym and n.sym.kind == skError and suggestVersion == 0:
       # consider 'foo.|' where 'foo' is some not imported module.
-      let fullPath = findModule(n.sym.name.s, n.info.toFullPath)
+      let fullPath = findModule(c.config, n.sym.name.s, n.info.toFullPath)
       if fullPath.len == 0:
         # error: no known module name:
         typ = nil
       else:
-        let m = gImportModule(c.graph, c.module, fullpath.fileInfoIdx, c.cache)
+        let m = gImportModule(c.graph, c.module, fileInfoIdx(c.config, fullpath), c.cache)
         if m == nil: typ = nil
         else:
           for it in items(n.sym.tab):
             if filterSym(it, field, pm):
-              outputs.add(symToSuggest(it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -100))
-          outputs.add(symToSuggest(m, isLocal=false, ideMod, n.info, 100, PrefixMatch.None,
+              outputs.add(symToSuggest(c.config, it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -100))
+          outputs.add(symToSuggest(c.config, m, isLocal=false, ideMod, n.info, 100, PrefixMatch.None,
             c.inTypeContext > 0, -99))
 
   if typ == nil:
@@ -363,11 +363,11 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions)
         # all symbols accessible, because we are in the current module:
         for it in items(c.topLevelScope.symbols):
           if filterSym(it, field, pm):
-            outputs.add(symToSuggest(it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99))
+            outputs.add(symToSuggest(c.config, it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99))
       else:
         for it in items(n.sym.tab):
           if filterSym(it, field, pm):
-            outputs.add(symToSuggest(it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99))
+            outputs.add(symToSuggest(c.config, it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99))
     else:
       # fallback:
       suggestEverything(c, n, field, outputs)
@@ -426,29 +426,29 @@ when defined(nimsuggest):
     s.allUsages.add(info)
 
 var
-  lastLineInfo*: TLineInfo
+  lastLineInfo*: TLineInfo # XXX global here
 
-proc findUsages(info: TLineInfo; s: PSym; usageSym: var PSym) =
+proc findUsages(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym) =
   if suggestVersion == 1:
     if usageSym == nil and isTracked(info, s.name.s.len):
       usageSym = s
-      suggestResult(symToSuggest(s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0))
+      suggestResult(symToSuggest(conf, s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0))
     elif s == usageSym:
       if lastLineInfo != info:
-        suggestResult(symToSuggest(s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0))
+        suggestResult(symToSuggest(conf, s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0))
       lastLineInfo = info
 
 when defined(nimsuggest):
-  proc listUsages*(s: PSym) =
+  proc listUsages*(conf: ConfigRef; s: PSym) =
     #echo "usages ", len(s.allUsages)
     for info in s.allUsages:
       let x = if info == s.info and info.col == s.info.col: ideDef else: ideUse
-      suggestResult(symToSuggest(s, isLocal=false, x, info, 100, PrefixMatch.None, false, 0))
+      suggestResult(symToSuggest(conf, s, isLocal=false, x, info, 100, PrefixMatch.None, false, 0))
 
-proc findDefinition(info: TLineInfo; s: PSym) =
+proc findDefinition(conf: ConfigRef; info: TLineInfo; s: PSym) =
   if s.isNil: return
   if isTracked(info, s.name.s.len):
-    suggestResult(symToSuggest(s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0))
+    suggestResult(symToSuggest(conf, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0))
     suggestQuit()
 
 proc ensureIdx[T](x: var T, y: int) =
@@ -457,7 +457,7 @@ proc ensureIdx[T](x: var T, y: int) =
 proc ensureSeq[T](x: var seq[T]) =
   if x == nil: newSeq(x, 0)
 
-proc suggestSym*(info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.inline.} =
+proc suggestSym*(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.inline.} =
   ## misnamed: should be 'symDeclared'
   when defined(nimsuggest):
     if suggestVersion == 0:
@@ -466,44 +466,44 @@ proc suggestSym*(info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.in
       else:
         s.addNoDup(info)
 
-    if gIdeCmd == ideUse:
-      findUsages(info, s, usageSym)
-    elif gIdeCmd == ideDef:
-      findDefinition(info, s)
-    elif gIdeCmd == ideDus and s != nil:
+    if conf.ideCmd == ideUse:
+      findUsages(conf, info, s, usageSym)
+    elif conf.ideCmd == ideDef:
+      findDefinition(conf, info, s)
+    elif conf.ideCmd == ideDus and s != nil:
       if isTracked(info, s.name.s.len):
-        suggestResult(symToSuggest(s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0))
-      findUsages(info, s, usageSym)
-    elif gIdeCmd == ideHighlight and info.fileIndex == gTrackPos.fileIndex:
-      suggestResult(symToSuggest(s, isLocal=false, ideHighlight, info, 100, PrefixMatch.None, false, 0))
-    elif gIdeCmd == ideOutline and info.fileIndex == gTrackPos.fileIndex and
+        suggestResult(symToSuggest(conf, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0))
+      findUsages(conf, info, s, usageSym)
+    elif conf.ideCmd == ideHighlight and info.fileIndex == gTrackPos.fileIndex:
+      suggestResult(symToSuggest(conf, s, isLocal=false, ideHighlight, info, 100, PrefixMatch.None, false, 0))
+    elif conf.ideCmd == ideOutline and info.fileIndex == gTrackPos.fileIndex and
         isDecl:
-      suggestResult(symToSuggest(s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0))
+      suggestResult(symToSuggest(conf, s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0))
 
-proc warnAboutDeprecated(info: TLineInfo; s: PSym) =
+proc warnAboutDeprecated(conf: ConfigRef; info: TLineInfo; s: PSym) =
   if s.kind in routineKinds:
     let n = s.ast[pragmasPos]
     if n.kind != nkEmpty:
       for it in n:
         if whichPragma(it) == wDeprecated and it.safeLen == 2 and
             it[1].kind in {nkStrLit..nkTripleStrLit}:
-          message(info, warnDeprecated, it[1].strVal & "; " & s.name.s)
+          message(conf, info, warnDeprecated, it[1].strVal & "; " & s.name.s)
           return
-  message(info, warnDeprecated, s.name.s)
+  message(conf, info, warnDeprecated, s.name.s)
 
-proc markUsed(info: TLineInfo; s: PSym; usageSym: var PSym) =
+proc markUsed(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym) =
   incl(s.flags, sfUsed)
   if s.kind == skEnumField and s.owner != nil:
     incl(s.owner.flags, sfUsed)
   if {sfDeprecated, sfError} * s.flags != {}:
-    if sfDeprecated in s.flags: warnAboutDeprecated(info, s)
-    if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s)
+    if sfDeprecated in s.flags: warnAboutDeprecated(conf, info, s)
+    if sfError in s.flags: localError(conf, info,  "usage of '$1' is a user-defined error" % s.name.s)
   when defined(nimsuggest):
-    suggestSym(info, s, usageSym, false)
+    suggestSym(conf, info, s, usageSym, false)
 
-proc useSym*(sym: PSym; usageSym: var PSym): PNode =
+proc useSym*(conf: ConfigRef; sym: PSym; usageSym: var PSym): PNode =
   result = newSymNode(sym)
-  markUsed(result.info, sym, usageSym)
+  markUsed(conf, result.info, sym, usageSym)
 
 proc safeSemExpr*(c: PContext, n: PNode): PNode =
   # use only for idetools support!
@@ -534,9 +534,9 @@ proc suggestExprNoCheck*(c: PContext, n: PNode) =
   if c.compilesContextId > 0: return
   inc(c.compilesContextId)
   var outputs: Suggestions = @[]
-  if gIdeCmd == ideSug:
+  if c.config.ideCmd == ideSug:
     sugExpr(c, n, outputs)
-  elif gIdeCmd == ideCon:
+  elif c.config.ideCmd == ideCon:
     if n.kind in nkCallKinds:
       var a = copyNode(n)
       var x = safeSemExpr(c, n.sons[0])
@@ -550,8 +550,8 @@ proc suggestExprNoCheck*(c: PContext, n: PNode) =
       suggestCall(c, a, n, outputs)
 
   dec(c.compilesContextId)
-  if outputs.len > 0 and gIdeCmd in {ideSug, ideCon, ideDef}:
-    produceOutput(outputs)
+  if outputs.len > 0 and c.config.ideCmd in {ideSug, ideCon, ideDef}:
+    produceOutput(outputs, c.config)
     suggestQuit()
 
 proc suggestExpr*(c: PContext, n: PNode) =
@@ -570,11 +570,11 @@ proc suggestStmt*(c: PContext, n: PNode) =
 proc suggestEnum*(c: PContext; n: PNode; t: PType) =
   var outputs: Suggestions = @[]
   suggestSymList(c, t.n, nil, n.info, outputs)
-  produceOutput(outputs)
+  produceOutput(outputs, c.config)
   if outputs.len > 0: suggestQuit()
 
 proc suggestSentinel*(c: PContext) =
-  if gIdeCmd != ideSug or c.module.position != gTrackPos.fileIndex.int32: return
+  if c.config.ideCmd != ideSug or c.module.position != gTrackPos.fileIndex.int32: return
   if c.compilesContextId > 0: return
   inc(c.compilesContextId)
   var outputs: Suggestions = @[]
@@ -587,7 +587,7 @@ proc suggestSentinel*(c: PContext) =
     for it in items(scope.symbols):
       var pm: PrefixMatch
       if filterSymNoOpr(it, nil, pm):
-        outputs.add(symToSuggest(it, isLocal = isLocal, ideSug, newLineInfo(gTrackPos.fileIndex, -1, -1), 0, PrefixMatch.None, false, scopeN))
+        outputs.add(symToSuggest(c.config, it, isLocal = isLocal, ideSug, newLineInfo(gTrackPos.fileIndex, -1, -1), 0, PrefixMatch.None, false, scopeN))
 
   dec(c.compilesContextId)
-  produceOutput(outputs)
+  produceOutput(outputs, c.config)
diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim
index 974df50fb..4bc153e46 100644
--- a/compiler/syntaxes.nim
+++ b/compiler/syntaxes.nim
@@ -11,7 +11,7 @@
 
 import
   strutils, llstream, ast, astalgo, idents, lexer, options, msgs, parser,
-  filters, filter_tmpl, renderer
+  filters, filter_tmpl, renderer, configuration
 
 type
   TFilterKind* = enum
@@ -30,12 +30,14 @@ type
     skin*: TParserKind
     parser*: TParser
 
+template config(p: TParsers): ConfigRef = p.parser.lex.config
+
 proc parseAll*(p: var TParsers): PNode =
   case p.skin
   of skinStandard, skinStrongSpaces:
     result = parser.parseAll(p.parser)
   of skinEndX:
-    internalError("parser to implement")
+    internalError(p.config, "parser to implement")
     result = ast.emptyNode
 
 proc parseTopLevelStmt*(p: var TParsers): PNode =
@@ -43,7 +45,7 @@ proc parseTopLevelStmt*(p: var TParsers): PNode =
   of skinStandard, skinStrongSpaces:
     result = parser.parseTopLevelStmt(p.parser)
   of skinEndX:
-    internalError("parser to implement")
+    internalError(p.config, "parser to implement")
     result = ast.emptyNode
 
 proc utf8Bom(s: string): int =
@@ -86,42 +88,44 @@ proc getFilter(ident: PIdent): TFilterKind =
       return i
   result = filtNone
 
-proc getParser(ident: PIdent): TParserKind =
+proc getParser(conf: ConfigRef; n: PNode; ident: PIdent): TParserKind =
   for i in countup(low(TParserKind), high(TParserKind)):
     if cmpIgnoreStyle(ident.s, parserNames[i]) == 0:
       return i
-  rawMessage(errInvalidDirectiveX, ident.s)
+  localError(conf, n.info, "unknown parser: " & ident.s)
 
-proc getCallee(n: PNode): PIdent =
+proc getCallee(conf: ConfigRef; n: PNode): PIdent =
   if n.kind in nkCallKinds and n.sons[0].kind == nkIdent:
     result = n.sons[0].ident
   elif n.kind == nkIdent:
     result = n.ident
   else:
-    rawMessage(errXNotAllowedHere, renderTree(n))
+    localError(conf, n.info, "invalid filter: " & renderTree(n))
 
 proc applyFilter(p: var TParsers, n: PNode, filename: string,
                  stdin: PLLStream): PLLStream =
-  var ident = getCallee(n)
+  var ident = getCallee(p.config, n)
   var f = getFilter(ident)
   case f
   of filtNone:
-    p.skin = getParser(ident)
+    p.skin = getParser(p.config, n, ident)
     result = stdin
   of filtTemplate:
-    result = filterTmpl(stdin, filename, n)
+    result = filterTmpl(stdin, filename, n, p.config)
   of filtStrip:
-    result = filterStrip(stdin, filename, n)
+    result = filterStrip(p.config, stdin, filename, n)
   of filtReplace:
-    result = filterReplace(stdin, filename, n)
+    result = filterReplace(p.config, stdin, filename, n)
   if f != filtNone:
-    if hintCodeBegin in gNotes:
-      rawMessage(hintCodeBegin, [])
-      msgWriteln(result.s)
-      rawMessage(hintCodeEnd, [])
+    assert p.config != nil
+    if hintCodeBegin in p.config.notes:
+      rawMessage(p.config, hintCodeBegin, [])
+      msgWriteln(p.config, result.s)
+      rawMessage(p.config, hintCodeEnd, [])
 
 proc evalPipe(p: var TParsers, n: PNode, filename: string,
               start: PLLStream): PLLStream =
+  assert p.config != nil
   result = start
   if n.kind == nkEmpty: return
   if n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "|":
@@ -137,10 +141,12 @@ proc evalPipe(p: var TParsers, n: PNode, filename: string,
 
 proc openParsers*(p: var TParsers, fileIdx: FileIndex, inputstream: PLLStream;
                   cache: IdentCache; config: ConfigRef) =
+  assert config != nil
   var s: PLLStream
   p.skin = skinStandard
   let filename = fileIdx.toFullPathConsiderDirty
   var pipe = parsePipe(filename, inputstream, cache, config)
+  p.config() = config
   if pipe != nil: s = evalPipe(p, pipe, filename, inputstream)
   else: s = inputstream
   case p.skin
@@ -158,7 +164,7 @@ proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode
     f: File
   let filename = fileIdx.toFullPathConsiderDirty
   if not open(f, filename):
-    rawMessage(errCannotOpenFile, filename)
+    rawMessage(config, errGenerated, "cannot open file: " & filename)
     return
   openParsers(p, fileIdx, llStreamOpen(f), cache, config)
   result = parseAll(p)
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 75c7f2b6c..c2add13ff 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -19,9 +19,10 @@
 # * transforms 'defer' into a 'try finally' statement
 
 import
-  intsets, strutils, options, ast, astalgo, trees, treetab, msgs, os, lookups,
+  intsets, strutils, options, ast, astalgo, trees, treetab, msgs, lookups,
   idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread,
-  lambdalifting, sempass2, lowerings, destroyer, liftlocals, closureiters
+  lambdalifting, sempass2, lowerings, destroyer, liftlocals, closureiters,
+  modulegraphs
 
 type
   PTransNode* = distinct PNode
@@ -44,6 +45,7 @@ type
     nestedProcs: int         # > 0 if we are in a nested proc
     contSyms, breakSyms: seq[PSym]  # to transform 'continue' and 'break'
     deferDetected, tooEarly, needsDestroyPass: bool
+    graph: ModuleGraph
   PTransf = ref TTransfContext
 
 proc newTransNode(a: PNode): PTransNode {.inline.} =
@@ -84,7 +86,7 @@ proc pushTransCon(c: PTransf, t: PTransCon) =
   c.transCon = t
 
 proc popTransCon(c: PTransf) =
-  if (c.transCon == nil): internalError("popTransCon")
+  if (c.transCon == nil): internalError(c.graph.config, "popTransCon")
   c.transCon = c.transCon.next
 
 proc getCurrOwner(c: PTransf): PSym =
@@ -97,7 +99,7 @@ proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode =
   incl(r.flags, sfFromGeneric)
   let owner = getCurrOwner(c)
   if owner.isIterator and not c.tooEarly:
-    result = freshVarForClosureIter(r, owner)
+    result = freshVarForClosureIter(c.graph, r, owner)
   else:
     result = newSymNode(r)
 
@@ -118,10 +120,10 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
   if s.typ != nil and s.typ.callConv == ccClosure:
     if s.kind == skIterator:
       if c.tooEarly: return n
-      else: return liftIterSym(n, getCurrOwner(c))
+      else: return liftIterSym(c.graph, n, getCurrOwner(c))
     elif s.kind in {skProc, skFunc, skConverter, skMethod} and not c.tooEarly:
       # top level .closure procs are still somewhat supported for 'Nake':
-      return makeClosure(s, nil, n.info)
+      return makeClosure(c.graph, s, nil, n.info)
   #elif n.sym.kind in {skVar, skLet} and n.sym.typ.callConv == ccClosure:
   #  echo n.info, " come heer for ", c.tooEarly
   #  if not c.tooEarly:
@@ -130,7 +132,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
   if sfBorrow in s.flags and s.kind in routineKinds:
     # simply exchange the symbol:
     b = s.getBody
-    if b.kind != nkSym: internalError(n.info, "wrong AST for borrowed symbol")
+    if b.kind != nkSym: internalError(c.graph.config, n.info, "wrong AST for borrowed symbol")
     b = newSymNode(b.sym, n.info)
   else:
     b = n
@@ -151,7 +153,7 @@ proc transformSym(c: PTransf, n: PNode): PTransNode =
 proc freshVar(c: PTransf; v: PSym): PNode =
   let owner = getCurrOwner(c)
   if owner.isIterator and not c.tooEarly:
-    result = freshVarForClosureIter(v, owner)
+    result = freshVarForClosureIter(c.graph, v, owner)
   else:
     var newVar = copySym(v)
     incl(newVar.flags, sfFromGeneric)
@@ -166,11 +168,11 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode =
       result[i] = PTransNode(it)
     elif it.kind == nkIdentDefs:
       if it.sons[0].kind == nkSym:
-        internalAssert(it.len == 3)
+        internalAssert(c.graph.config, it.len == 3)
         let x = freshVar(c, it.sons[0].sym)
         idNodeTablePut(c.transCon.mapping, it.sons[0].sym, x)
         var defs = newTransNode(nkIdentDefs, it.info, 3)
-        if importantComments():
+        if importantComments(c.graph.config):
           # keep documentation information:
           PNode(defs).comment = it.comment
         defs[0] = x.PTransNode
@@ -184,7 +186,7 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode =
         result[i] = transform(c, it)
     else:
       if it.kind != nkVarTuple:
-        internalError(it.info, "transformVarSection: not nkVarTuple")
+        internalError(c.graph.config, it.info, "transformVarSection: not nkVarTuple")
       var L = sonsLen(it)
       var defs = newTransNode(it.kind, it.info, L)
       for j in countup(0, L-3):
@@ -203,9 +205,9 @@ proc transformConstSection(c: PTransf, v: PNode): PTransNode =
     if it.kind == nkCommentStmt:
       result[i] = PTransNode(it)
     else:
-      if it.kind != nkConstDef: internalError(it.info, "transformConstSection")
+      if it.kind != nkConstDef: internalError(c.graph.config, it.info, "transformConstSection")
       if it.sons[0].kind != nkSym:
-        internalError(it.info, "transformConstSection")
+        internalError(c.graph.config, it.info, "transformConstSection")
 
       result[i] = PTransNode(it)
 
@@ -301,7 +303,7 @@ proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
   # XXX: BUG: what if `n` is an expression with side-effects?
   for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
     add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
-        transform(c, newTupleAccess(n, i))))
+        transform(c, newTupleAccess(c.graph, n, i))))
 
 proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
   case n.kind
@@ -356,7 +358,7 @@ proc transformYield(c: PTransf, n: PNode): PTransNode =
 
 proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
   result = transformSons(c, n)
-  if gCmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return
+  if c.graph.config.cmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return
   var n = result.PNode
   case n.sons[0].kind
   of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
@@ -382,21 +384,21 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
       if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
         PNode(result).typ = n.typ
 
-proc generateThunk(prc: PNode, dest: PType): PNode =
+proc generateThunk(c: PTransf; prc: PNode, dest: PType): PNode =
   ## Converts 'prc' into '(thunk, nil)' so that it's compatible with
   ## a closure.
 
   # we cannot generate a proper thunk here for GC-safety reasons
   # (see internal documentation):
-  if gCmd == cmdCompileToJS: return prc
+  if c.graph.config.cmd == cmdCompileToJS: return prc
   result = newNodeIT(nkClosure, prc.info, dest)
   var conv = newNodeIT(nkHiddenSubConv, prc.info, dest)
   conv.add(emptyNode)
   conv.add(prc)
   if prc.kind == nkClosure:
-    internalError(prc.info, "closure to closure created")
+    internalError(c.graph.config, prc.info, "closure to closure created")
   result.add(conv)
-  result.add(newNodeIT(nkNilLit, prc.info, getSysType(tyNil)))
+  result.add(newNodeIT(nkNilLit, prc.info, getSysType(c.graph, prc.info, tyNil)))
 
 proc transformConv(c: PTransf, n: PNode): PTransNode =
   # numeric types need range checks:
@@ -481,7 +483,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
   of tyProc:
     result = transformSons(c, n)
     if dest.callConv == ccClosure and source.callConv == ccDefault:
-      result = generateThunk(result[1].PNode, dest).PTransNode
+      result = generateThunk(c, result[1].PNode, dest).PTransNode
   else:
     result = transformSons(c, n)
 
@@ -513,7 +515,7 @@ proc findWrongOwners(c: PTransf, n: PNode) =
   if n.kind == nkVarSection:
     let x = n.sons[0].sons[0]
     if x.kind == nkSym and x.sym.owner != getCurrOwner(c):
-      internalError(x.info, "bah " & x.sym.name.s & " " &
+      internalError(c.graph.config, x.info, "bah " & x.sym.name.s & " " &
         x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
   else:
     for i in 0 ..< safeLen(n): findWrongOwners(c, n.sons[i])
@@ -521,7 +523,7 @@ proc findWrongOwners(c: PTransf, n: PNode) =
 proc transformFor(c: PTransf, n: PNode): PTransNode =
   # generate access statements for the parameters (unless they are constant)
   # put mapping from formal parameters to actual parameters
-  if n.kind != nkForStmt: internalError(n.info, "transformFor")
+  if n.kind != nkForStmt: internalError(c.graph.config, n.info, "transformFor")
 
   var length = sonsLen(n)
   var call = n.sons[length - 2]
@@ -539,7 +541,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
     n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
     if not c.tooEarly:
       n.sons[length-2] = transform(c, n.sons[length-2]).PNode
-      result[1] = lambdalifting.liftForLoop(n, getCurrOwner(c)).PTransNode
+      result[1] = lambdalifting.liftForLoop(c.graph, n, getCurrOwner(c)).PTransNode
     else:
       result[1] = newNode(nkEmpty).PTransNode
     discard c.breakSyms.pop
@@ -689,7 +691,7 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
         while (j < sonsLen(n)):
           let b = transform(c, n.sons[j]).PNode
           if not isConstExpr(b): break
-          a = evalOp(op.magic, n, a, b, nil)
+          a = evalOp(op.magic, n, a, b, nil, c.graph)
           inc(j)
       add(result, a.PTransNode)
     if len(result) == 2: result = result[1]
@@ -708,18 +710,18 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
         let t = lastSon(s.sons[0].sym.ast)
         if t.kind != nkSym or sfDispatcher notin t.sym.flags:
           methodDef(s.sons[0].sym, false)
-      result = methodCall(s).PTransNode
+      result = methodCall(s, c.graph.config).PTransNode
     else:
       result = s.PTransNode
 
 proc transformExceptBranch(c: PTransf, n: PNode): PTransNode =
   result = transformSons(c, n)
-  if n[0].isInfixAs() and (not isImportedException(n[0][1].typ)):
+  if n[0].isInfixAs() and not isImportedException(n[0][1].typ, c.graph.config):
     let excTypeNode = n[0][1]
     let actions = newTransNode(nkStmtListExpr, n[1], 2)
     # Generating `let exc = (excType)(getCurrentException())`
     # -> getCurrentException()
-    let excCall = PTransNode(callCodegenProc("getCurrentException", ast.emptyNode))
+    let excCall = PTransNode(callCodegenProc(c.graph, "getCurrentException", ast.emptyNode))
     # -> (excType)
     let convNode = newTransNode(nkHiddenSubConv, n[1].info, 2)
     convNode[0] = PTransNode(ast.emptyNode)
@@ -748,10 +750,10 @@ proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
   result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket} and
       cnst.len != 0
 
-proc commonOptimizations*(c: PSym, n: PNode): PNode =
+proc commonOptimizations*(g: ModuleGraph; c: PSym, n: PNode): PNode =
   result = n
   for i in 0 ..< n.safeLen:
-    result.sons[i] = commonOptimizations(c, n.sons[i])
+    result.sons[i] = commonOptimizations(g, c, n.sons[i])
   var op = getMergeOp(n)
   if (op != nil) and (op.magic != mNone) and (sonsLen(n) >= 3):
     result = newNodeIT(nkCall, n.info, n.typ)
@@ -766,12 +768,12 @@ proc commonOptimizations*(c: PSym, n: PNode): PNode =
         while j < sonsLen(args):
           let b = args.sons[j]
           if not isConstExpr(b): break
-          a = evalOp(op.magic, result, a, b, nil)
+          a = evalOp(op.magic, result, a, b, nil, g)
           inc(j)
       add(result, a)
     if len(result) == 2: result = result[1]
   else:
-    var cnst = getConstExpr(c, n)
+    var cnst = getConstExpr(c, n, g)
     # we inline constants if they are not complex constants:
     if cnst != nil and not dontInlineConstant(n, cnst):
       result = cnst
@@ -888,7 +890,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
       let L = n.len-1
       result[L] = transform(c, n.sons[L])
     # XXX comment handling really sucks:
-    if importantComments():
+    if importantComments(c.graph.config):
       PNode(result).comment = n.comment
   of nkClosure:
     # it can happen that for-loop-inlining produced a fresh
@@ -905,7 +907,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
   when false:
     if oldDeferAnchor != nil: c.deferAnchor = oldDeferAnchor
 
-  var cnst = getConstExpr(c.module, PNode(result))
+  var cnst = getConstExpr(c.module, PNode(result), c.graph)
   # we inline constants if they are not complex constants:
   if cnst != nil and not dontInlineConstant(n, cnst):
     result = PTransNode(cnst) # do not miss an optimization
@@ -920,11 +922,12 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
   popTransCon(c)
   incl(result.flags, nfTransf)
 
-proc openTransf(module: PSym, filename: string): PTransf =
+proc openTransf(g: ModuleGraph; module: PSym, filename: string): PTransf =
   new(result)
   result.contSyms = @[]
   result.breakSyms = @[]
   result.module = module
+  result.graph = g
 
 proc flattenStmts(n: PNode) =
   var goOn = true
@@ -967,48 +970,50 @@ template liftDefer(c, root) =
   if c.deferDetected:
     liftDeferAux(root)
 
-proc transformBody*(module: PSym, features: set[Feature], n: PNode, prc: PSym): PNode =
-  result = n
-  if nfTransf notin n.flags and prc.kind notin {skTemplate}:
-    var c = openTransf(module, "")
-    result = liftLambdas(features, prc, result, c.tooEarly)
+proc transformBody*(g: ModuleGraph; module: PSym, n: PNode, prc: PSym): PNode =
+  if nfTransf in n.flags or prc.kind in {skTemplate}:
+    result = n
+  else:
+    var c = openTransf(g, module, "")
+    result = liftLambdas(g, prc, n, c.tooEarly)
+    #result = n
     result = processTransf(c, result, prc)
     liftDefer(c, result)
-
-    when useEffectSystem: trackProc(prc, result)
-    result = liftLocalsIfRequested(prc, result)
+    #result = liftLambdas(prc, result)
+    when useEffectSystem: trackProc(g, prc, result)
+    result = liftLocalsIfRequested(prc, result, g.config)
     if c.needsDestroyPass: #and newDestructors:
-      result = injectDestructorCalls(prc, result)
+      result = injectDestructorCalls(g, prc, result)
 
-    if prc.isIterator and oldIterTransf notin features:
-      result = transformClosureIterator(prc, result)
+    if prc.isIterator and oldIterTransf notin g.config.features:
+      result = g.transformClosureIterator(prc, result)
 
     incl(result.flags, nfTransf)
       #if prc.name.s == "testbody":
     #  echo renderTree(result)
 
-proc transformStmt*(module: PSym, n: PNode): PNode =
+proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
   if nfTransf in n.flags:
     result = n
   else:
-    var c = openTransf(module, "")
+    var c = openTransf(g, module, "")
     result = processTransf(c, n, module)
     liftDefer(c, result)
     #result = liftLambdasForTopLevel(module, result)
-    when useEffectSystem: trackTopLevelStmt(module, result)
+    when useEffectSystem: trackTopLevelStmt(g, module, result)
     #if n.info ?? "temp.nim":
     #  echo renderTree(result, {renderIds})
     if c.needsDestroyPass:
-      result = injectDestructorCalls(module, result)
+      result = injectDestructorCalls(g, module, result)
     incl(result.flags, nfTransf)
 
-proc transformExpr*(module: PSym, n: PNode): PNode =
+proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode =
   if nfTransf in n.flags:
     result = n
   else:
-    var c = openTransf(module, "")
+    var c = openTransf(g, module, "")
     result = processTransf(c, n, module)
     liftDefer(c, result)
     if c.needsDestroyPass:
-      result = injectDestructorCalls(module, result)
+      result = injectDestructorCalls(g, module, result)
     incl(result.flags, nfTransf)
diff --git a/compiler/types.nim b/compiler/types.nim
index b9b6ab33c..b5f4fbf54 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -10,7 +10,7 @@
 # this module contains routines for accessing and iterating over types
 
 import
-  intsets, ast, astalgo, trees, msgs, strutils, platform, renderer
+  intsets, ast, astalgo, trees, msgs, strutils, platform, renderer, options
 
 type
   TPreferedDesc* = enum
@@ -92,8 +92,9 @@ proc getOrdValue*(n: PNode): BiggestInt =
   of nkNilLit: result = 0
   of nkHiddenStdConv: result = getOrdValue(n.sons[1])
   else:
-    localError(n.info, errOrdinalTypeExpected)
-    result = 0
+    #localError(n.info, errOrdinalTypeExpected)
+    # XXX check usages of getOrdValue
+    result = high(BiggestInt)
 
 proc isIntLit*(t: PType): bool {.inline.} =
   result = t.kind == tyInt and t.n != nil and t.n.kind == nkIntLit
@@ -105,14 +106,14 @@ proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string =
   result = sym.owner.name.s & '.' & sym.name.s & '('
   var n = sym.typ.n
   for i in countup(1, sonsLen(n) - 1):
-    var p = n.sons[i]
+    let p = n.sons[i]
     if p.kind == nkSym:
       add(result, p.sym.name.s)
       add(result, ": ")
       add(result, typeToString(p.sym.typ, prefer))
       if i != sonsLen(n)-1: add(result, ", ")
     else:
-      internalError("getProcHeader")
+      result.add renderTree(p)
   add(result, ')')
   if n.sons[0].typ != nil:
     result.add(": " & typeToString(n.sons[0].typ, prefer))
@@ -195,10 +196,10 @@ proc searchTypeNodeForAux(n: PNode, p: TTypePredicate,
       of nkOfBranch, nkElse:
         result = searchTypeNodeForAux(lastSon(n.sons[i]), p, marker)
         if result: return
-      else: internalError("searchTypeNodeForAux(record case branch)")
+      else: discard
   of nkSym:
     result = searchTypeForAux(n.sym.typ, p, marker)
-  else: internalError(n.info, "searchTypeNodeForAux()")
+  else: discard
 
 proc searchTypeForAux(t: PType, predicate: TTypePredicate,
                       marker: var IntSet): bool =
@@ -244,7 +245,7 @@ proc analyseObjectWithTypeFieldAux(t: PType,
   if t == nil: return
   case t.kind
   of tyObject:
-    if (t.n != nil):
+    if t.n != nil:
       if searchTypeNodeForAux(t.n, isObjectWithTypeFieldPredicate, marker):
         return frEmbedded
     for i in countup(0, sonsLen(t) - 1):
@@ -453,16 +454,17 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
     if t.sons[0].kind == tyNone: result = "typedesc"
     else: result = "type " & typeToString(t.sons[0])
   of tyStatic:
-    internalAssert t.len > 0
     if prefer == preferGenericArg and t.n != nil:
       result = t.n.renderTree
     else:
-      result = "static[" & typeToString(t.sons[0]) & "]"
+      result = "static[" & (if t.len > 0: typeToString(t.sons[0]) else: "") & "]"
       if t.n != nil: result.add "(" & renderTree(t.n) & ")"
   of tyUserTypeClass:
-    internalAssert t.sym != nil and t.sym.owner != nil
-    if t.isResolvedUserTypeClass: return typeToString(t.lastSon)
-    return t.sym.owner.name.s
+    if t.sym != nil and t.sym.owner != nil:
+      if t.isResolvedUserTypeClass: return typeToString(t.lastSon)
+      return t.sym.owner.name.s
+    else:
+      result = "<invalid tyUserTypeClass>"
   of tyBuiltInTypeClass:
     result = case t.base.kind:
       of tyVar: "var"
@@ -496,7 +498,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
   of tyNot:
     result = "not " & typeToString(t.sons[0])
   of tyExpr:
-    internalAssert t.len == 0
+    #internalAssert t.len == 0
     result = "untyped"
   of tyFromExpr:
     result = renderTree(t.n)
@@ -616,9 +618,9 @@ proc firstOrd*(t: PType): BiggestInt =
     result = firstOrd(lastSon(t))
   of tyOrdinal:
     if t.len > 0: result = firstOrd(lastSon(t))
-    else: internalError("invalid kind for firstOrd(" & $t.kind & ')')
+    else: internalError(newPartialConfigRef(), "invalid kind for firstOrd(" & $t.kind & ')')
   else:
-    internalError("invalid kind for firstOrd(" & $t.kind & ')')
+    internalError(newPartialConfigRef(), "invalid kind for firstOrd(" & $t.kind & ')')
     result = 0
 
 proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt =
@@ -656,9 +658,9 @@ proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt =
   of tyProxy: result = 0
   of tyOrdinal:
     if t.len > 0: result = lastOrd(lastSon(t))
-    else: internalError("invalid kind for lastOrd(" & $t.kind & ')')
+    else: internalError(newPartialConfigRef(), "invalid kind for lastOrd(" & $t.kind & ')')
   else:
-    internalError("invalid kind for lastOrd(" & $t.kind & ')')
+    internalError(newPartialConfigRef(), "invalid kind for lastOrd(" & $t.kind & ')')
     result = 0
 
 proc lengthOrd*(t: PType): BiggestInt =
@@ -748,7 +750,7 @@ proc equalParam(a, b: PSym): TParamsEquality =
 
 proc sameConstraints(a, b: PNode): bool =
   if isNil(a) and isNil(b): return true
-  internalAssert a.len == b.len
+  if a.len != b.len: return false
   for i in 1 ..< a.len:
     if not exprStructuralEquivalent(a[i].sym.constraint,
                                     b[i].sym.constraint):
@@ -807,7 +809,8 @@ proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
           var y = b.n.sons[i].sym
           result = x.name.id == y.name.id
           if not result: break
-        else: internalError(a.n.info, "sameTuple")
+        else:
+          return false
     elif a.n != b.n and (a.n == nil or b.n == nil) and IgnoreTupleFields notin c.flags:
       result = false
 
@@ -997,7 +1000,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
     cycleCheck()
     result = sameTypeAux(a.lastSon, b.lastSon, c)
   of tyNone: result = false
-  of tyUnused, tyOptAsRef: internalError("sameFlags")
+  of tyUnused, tyOptAsRef: result = false
 
 proc sameBackendType*(x, y: PType): bool =
   var c = initSameTypeClosure()
@@ -1191,7 +1194,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
     # for now same as error node; we say it's a valid type as it should
     # prevent cascading errors:
     result = nil
-  of tyUnused, tyOptAsRef: internalError("typeAllowedAux")
+  of tyUnused, tyOptAsRef: result = t
 
 proc typeAllowed*(t: PType, kind: TSymKind; flags: TTypeAllowedFlags = {}): PType =
   # returns 'nil' on success and otherwise the part of the type that is
@@ -1280,7 +1283,8 @@ proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt =
         if res < 0: return res
         maxSize = max(maxSize, res)
         maxAlign = max(maxAlign, b)
-      else: internalError("computeRecSizeAux(record case branch)")
+      else:
+        return szIllegalRecursion
     currOffset = align(currOffset, maxAlign) + maxSize
     result = align(result, maxAlign) + maxSize
     a = maxAlign
@@ -1441,7 +1445,8 @@ proc getReturnType*(s: PSym): PType =
 
 proc getSize*(typ: PType): BiggestInt =
   result = computeSize(typ)
-  if result < 0: internalError("getSize: " & $typ.kind)
+  #if result < 0: internalError("getSize: " & $typ.kind)
+  # XXX review all usages of 'getSize'
 
 proc containsGenericTypeIter(t: PType, closure: RootRef): bool =
   case t.kind
@@ -1469,8 +1474,7 @@ proc baseOfDistinct*(t: PType): PType =
     while it.kind in {tyPtr, tyRef}:
       parent = it
       it = it.lastSon
-    if it.kind == tyDistinct:
-      internalAssert parent != nil
+    if it.kind == tyDistinct and parent != nil:
       parent.sons[0] = it.sons[0]
 
 proc safeInheritanceDiff*(a, b: PType): int =
@@ -1502,8 +1506,9 @@ type
 proc compatibleEffects*(formal, actual: PType): EffectsCompat =
   # for proc type compatibility checking:
   assert formal.kind == tyProc and actual.kind == tyProc
-  internalAssert formal.n.sons[0].kind == nkEffectList
-  internalAssert actual.n.sons[0].kind == nkEffectList
+  if formal.n.sons[0].kind != nkEffectList or
+     actual.n.sons[0].kind != nkEffectList:
+    return efTagsUnknown
 
   var spec = formal.n.sons[0]
   if spec.len != 0:
@@ -1628,14 +1633,14 @@ proc skipHiddenSubConv*(n: PNode): PNode =
   else:
     result = n
 
-proc typeMismatch*(info: TLineInfo, formal, actual: PType) =
+proc typeMismatch*(conf: ConfigRef; info: TLineInfo, formal, actual: PType) =
   if formal.kind != tyError and actual.kind != tyError:
     let named = typeToString(formal)
     let desc = typeToString(formal, preferDesc)
     let x = if named == desc: named else: named & " = " & desc
-    var msg = msgKindToString(errTypeMismatch) &
+    var msg = "type mismatch: got <" &
               typeToString(actual) & "> " &
-              msgKindToString(errButExpectedX) % [x]
+              "but expected '" & x & "'"
 
     if formal.kind == tyProc and actual.kind == tyProc:
       case compatibleEffects(formal, actual)
@@ -1650,4 +1655,4 @@ proc typeMismatch*(info: TLineInfo, formal, actual: PType) =
         msg.add "\n.tag effect is 'any tag allowed'"
       of efLockLevelsDiffer:
         msg.add "\nlock levels differ"
-    localError(info, errGenerated, msg)
+    localError(conf, info, msg)
diff --git a/compiler/typesrenderer.nim b/compiler/typesrenderer.nim
index 4a9b8d1a9..4d75d5d05 100644
--- a/compiler/typesrenderer.nim
+++ b/compiler/typesrenderer.nim
@@ -17,7 +17,6 @@ proc renderPlainSymbolName*(n: PNode): string =
   ## Use this on documentation name nodes to extract the *raw* symbol name,
   ## without decorations, parameters, or anything. That can be used as the base
   ## for the HTML hyperlinks.
-  result = ""
   case n.kind
   of nkPostfix, nkAccQuoted:
     result = renderPlainSymbolName(n[n.len-1])
@@ -28,7 +27,8 @@ proc renderPlainSymbolName*(n: PNode): string =
   of nkPragmaExpr:
     result = renderPlainSymbolName(n[0])
   else:
-    internalError(n.info, "renderPlainSymbolName() with " & $n.kind)
+    result = ""
+    #internalError(n.info, "renderPlainSymbolName() with " & $n.kind)
   assert(not result.isNil)
 
 proc renderType(n: PNode): string =
@@ -105,7 +105,8 @@ proc renderParamTypes(found: var seq[string], n: PNode) =
     for i in 0 ..< typePos:
       found.add(typeStr)
   else:
-    internalError(n.info, "renderParamTypes(found,n) with " & $n.kind)
+    found.add($n)
+    #internalError(n.info, "renderParamTypes(found,n) with " & $n.kind)
 
 proc renderParamTypes*(n: PNode, sep = defaultParamSeparator): string =
   ## Returns the types contained in `n` joined by `sep`.
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 27135d2e7..dcb4cefd7 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -19,7 +19,7 @@ import ast except getstr
 import
   strutils, astalgo, msgs, vmdef, vmgen, nimsets, types, passes,
   parser, vmdeps, idents, trees, renderer, options, transf, parseutils,
-  vmmarshal, gorgeimpl
+  vmmarshal, gorgeimpl, configuration
 
 from semfold import leValueConv, ordinalValToString
 from evaltempl import evalTemplate
@@ -61,7 +61,7 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) =
       while x != nil:
         inc calls
         x = x.next
-      msgWriteln($calls & " calls omitted\n")
+      msgWriteln(c.config, $calls & " calls omitted\n")
       return
     stackTraceAux(c, x.next, x.comesFrom, recursionLimit-1)
     var info = c.debug[pc]
@@ -78,19 +78,19 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) =
     if x.prc != nil:
       for k in 1..max(1, 25-s.len): add(s, ' ')
       add(s, x.prc.name.s)
-    msgWriteln(s)
+    msgWriteln(c.config, s)
 
 proc stackTrace(c: PCtx, tos: PStackFrame, pc: int,
-                msg: TMsgKind, arg = "", n: PNode = nil) =
-  msgWriteln("stack trace: (most recent call last)")
+                msg: string, n: PNode = nil) =
+  msgWriteln(c.config, "stack trace: (most recent call last)")
   stackTraceAux(c, tos, pc)
   # XXX test if we want 'globalError' for every mode
   let lineInfo = if n == nil: c.debug[pc] else: n.info
-  if c.mode == emRepl: globalError(lineInfo, msg, arg)
-  else: localError(lineInfo, msg, arg)
+  if c.mode == emRepl: globalError(c.config, lineInfo, msg)
+  else: localError(c.config, lineInfo, msg)
 
 proc bailOut(c: PCtx; tos: PStackFrame) =
-  stackTrace(c, tos, c.exceptionInstr, errUnhandledExceptionX,
+  stackTrace(c, tos, c.exceptionInstr, "unhandled exception: " &
              c.currentExceptionA.sons[3].skipColon.strVal)
 
 when not defined(nimComputedGoto):
@@ -314,7 +314,7 @@ proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int =
       return pc
   return -1
 
-proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
+proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
   if desttyp.kind == tyString:
     if dest.kind != rkNode:
       myreset(dest)
@@ -329,7 +329,7 @@ proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
         dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal
       else:
         for i in 0..<n.len:
-          if n.sons[i].kind != nkSym: internalError("opConv for enum")
+          if n.sons[i].kind != nkSym: internalError(c.config, "opConv for enum")
           let f = n.sons[i].sym
           if f.position == x:
             dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal
@@ -359,7 +359,7 @@ proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
     of tyChar:
       dest.node.strVal = $chr(src.intVal)
     else:
-      internalError("cannot convert to string " & desttyp.typeToString)
+      internalError(c.config, "cannot convert to string " & desttyp.typeToString)
   else:
     case skipTypes(desttyp, abstractRange).kind
     of tyInt..tyInt64:
@@ -408,9 +408,9 @@ template handleJmpBack() {.dirty.} =
     if allowInfiniteLoops in c.features:
       c.loopIterations = MaxLoopIterations
     else:
-      msgWriteln("stack trace: (most recent call last)")
+      msgWriteln(c.config, "stack trace: (most recent call last)")
       stackTraceAux(c, tos, pc)
-      globalError(c.debug[pc], errTooManyIterations)
+      globalError(c.config, c.debug[pc], errTooManyIterations)
   dec(c.loopIterations)
 
 proc recSetFlagIsRef(arg: PNode) =
@@ -440,6 +440,17 @@ proc setLenSeq(c: PCtx; node: PNode; newLen: int; info: TLineInfo) =
     for i in oldLen ..< newLen:
       node.sons[i] = newNodeI(typeKind, info)
 
+const
+  errIndexOutOfBounds = "index ouf of bounds"
+  errNilAccess = "attempt to access a nil address"
+  errOverOrUnderflow = "over- or underflow"
+  errConstantDivisionByZero = "division by zero"
+  errIllegalConvFromXtoY = "illegal conversion from '$1' to '$2'"
+  errTooManyIterations = "interpretation requires too many iterations; " &
+    "if you are sure this is not a bug in your code edit " &
+    "compiler/vmdef.MaxLoopIterations and rebuild the compiler"
+  errFieldXNotFound = "node lacks field: "
+
 proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
   var pc = start
   var tos = tos
@@ -453,7 +464,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     #if c.traceActive:
     when traceCode:
       echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra, " rb ", instr.regB, " rc ", instr.regC
-    #  message(c.debug[pc], warnUser, "Trace")
+    #  message(c.config, c.debug[pc], warnUser, "Trace")
 
     case instr.opcode
     of opcEof: return regs[ra]
@@ -586,7 +597,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       if regs[rb].kind == rkNode:
         regs[ra].nodeAddr = addr(regs[rb].node)
       else:
-        stackTrace(c, tos, pc, errGenerated, "limited VM support for 'addr'")
+        stackTrace(c, tos, pc, "limited VM support for 'addr'")
     of opcLdDeref:
       # a = b[]
       let ra = instr.regA
@@ -629,7 +640,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         stackTrace(c, tos, pc, errOverOrUnderflow)
     of opcAddImmInt:
       decodeBImm(rkInt)
-      #message(c.debug[pc], warnUser, "came here")
+      #message(c.config, c.debug[pc], warnUser, "came here")
       #debug regs[rb].node
       let
         bVal = regs[rb].intVal
@@ -898,17 +909,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit)
                         else: copyTree(a.sym.ast)
       else:
-        stackTrace(c, tos, pc, errGenerated, "node is not a symbol")
+        stackTrace(c, tos, pc, "node is not a symbol")
     of opcEcho:
       let rb = instr.regB
       if rb == 1:
-        msgWriteln(regs[ra].node.strVal, {msgStdout})
+        msgWriteln(c.config, regs[ra].node.strVal, {msgStdout})
       else:
         var outp = ""
         for i in ra..ra+rb-1:
           #if regs[i].kind != rkNode: debug regs[i]
           outp.add(regs[i].node.strVal)
-        msgWriteln(outp, {msgStdout})
+        msgWriteln(c.config, outp, {msgStdout})
     of opcContainsSet:
       decodeBC(rkInt)
       regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].regToNode))
@@ -937,9 +948,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       let rc = instr.regC
       if not (leValueConv(regs[rb].regToNode, regs[ra].regToNode) and
               leValueConv(regs[ra].regToNode, regs[rc].regToNode)):
-        stackTrace(c, tos, pc, errGenerated,
-          msgKindToString(errIllegalConvFromXtoY) % [
-          $regs[ra].regToNode, "[" & $regs[rb].regToNode & ".." & $regs[rc].regToNode & "]"])
+        stackTrace(c, tos, pc,
+          errIllegalConvFromXtoY % [
+             $regs[ra].regToNode, "[" & $regs[rb].regToNode & ".." & $regs[rc].regToNode & "]"])
     of opcIndCall, opcIndCallAsgn:
       # dest = call regStart, n; where regStart = fn, arg1, ...
       let rb = instr.regB
@@ -955,20 +966,20 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
                  currentLineInfo: c.debug[pc]))
       elif sfImportc in prc.flags:
         if allowFFI notin c.features:
-          globalError(c.debug[pc], errGenerated, "VM not allowed to do FFI")
+          globalError(c.config, c.debug[pc], "VM not allowed to do FFI")
         # we pass 'tos.slots' instead of 'regs' so that the compiler can keep
         # 'regs' in a register:
         when hasFFI:
           let prcValue = c.globals.sons[prc.position-1]
           if prcValue.kind == nkEmpty:
-            globalError(c.debug[pc], errGenerated, "canot run " & prc.name.s)
+            globalError(c.config, c.debug[pc], "canot run " & prc.name.s)
           let newValue = callForeignFunction(prcValue, prc.typ, tos.slots,
                                              rb+1, rc-1, c.debug[pc])
           if newValue.kind != nkEmpty:
             assert instr.opcode == opcIndCallAsgn
             putIntoReg(regs[ra], newValue)
         else:
-          globalError(c.debug[pc], errGenerated, "VM not built with FFI support")
+          globalError(c.config, c.debug[pc], "VM not built with FFI support")
       elif prc.kind != skTemplate:
         let newPc = compile(c, prc)
         # tricky: a recursion is also a jump back, so we use the same
@@ -978,7 +989,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos)
         newSeq(newFrame.slots, prc.offset+ord(isClosure))
         if not isEmptyType(prc.typ.sons[0]) or prc.kind == skMacro:
-          putIntoReg(newFrame.slots[0], getNullValue(prc.typ.sons[0], prc.info))
+          putIntoReg(newFrame.slots[0], getNullValue(prc.typ.sons[0], prc.info, c.config))
         for i in 1 .. rc-1:
           newFrame.slots[i] = regs[rb+i]
         if isClosure:
@@ -1000,7 +1011,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
           let node = regs[rb+i].regToNode
           node.info = c.debug[pc]
           macroCall.add(node)
-        var a = evalTemplate(macroCall, prc, genSymOwner)
+        var a = evalTemplate(macroCall, prc, genSymOwner, c.config)
         if a.kind == nkStmtList and a.len == 1: a = a[0]
         a.recSetFlagIsRef
         ensureKind(rkNode)
@@ -1085,7 +1096,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcNew:
       ensureKind(rkNode)
       let typ = c.types[instr.regBx - wordExcess]
-      regs[ra].node = getNullValue(typ, c.debug[pc])
+      regs[ra].node = getNullValue(typ, c.debug[pc], c.config)
       regs[ra].node.flags.incl nfIsRef
     of opcNewSeq:
       let typ = c.types[instr.regBx - wordExcess]
@@ -1097,7 +1108,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       regs[ra].node.typ = typ
       newSeq(regs[ra].node.sons, count)
       for i in 0 ..< count:
-        regs[ra].node.sons[i] = getNullValue(typ.sons[0], c.debug[pc])
+        regs[ra].node.sons[i] = getNullValue(typ.sons[0], c.debug[pc], c.config)
     of opcNewStr:
       decodeB(rkNode)
       regs[ra].node = newNodeI(nkStrLit, c.debug[pc])
@@ -1109,7 +1120,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcLdNull:
       ensureKind(rkNode)
       let typ = c.types[instr.regBx - wordExcess]
-      regs[ra].node = getNullValue(typ, c.debug[pc])
+      regs[ra].node = getNullValue(typ, c.debug[pc], c.config)
       # opcLdNull really is the gist of the VM's problems: should it load
       # a fresh null to  regs[ra].node  or to regs[ra].node[]? This really
       # depends on whether regs[ra] represents the variable itself or wether
@@ -1156,7 +1167,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       regs[ra].node.strVal = renderTree(regs[rb].regToNode, {renderNoComments, renderDocComments})
     of opcQuit:
       if c.mode in {emRepl, emStaticExpr, emStaticStmt}:
-        message(c.debug[pc], hintQuitCalled)
+        message(c.config, c.debug[pc], hintQuitCalled)
         msgQuit(int8(getOrdValue(regs[ra].regToNode)))
       else:
         return TFullReg(kind: rkNone)
@@ -1182,14 +1193,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       if regs[ra].node.isNil: stackTrace(c, tos, pc, errNilAccess)
       else: c.setLenSeq(regs[ra].node, newLen, c.debug[pc])
     of opcReset:
-      internalError(c.debug[pc], "too implement")
+      internalError(c.config, c.debug[pc], "too implement")
     of opcNarrowS:
       decodeB(rkInt)
       let min = -(1.BiggestInt shl (rb-1))
       let max = (1.BiggestInt shl (rb-1))-1
       if regs[ra].intVal < min or regs[ra].intVal > max:
-        stackTrace(c, tos, pc, errGenerated,
-          msgKindToString(errUnhandledExceptionX) % "value out of range")
+        stackTrace(c, tos, pc, "unhandled exception: value out of range")
     of opcNarrowU:
       decodeB(rkInt)
       regs[ra].intVal = regs[ra].intVal and ((1'i64 shl rb)-1)
@@ -1223,7 +1233,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       if u.kind notin {nkEmpty..nkNilLit}:
         u.add(regs[rc].node)
       else:
-        stackTrace(c, tos, pc, errGenerated, "cannot add to node kind: " & $u.kind)
+        stackTrace(c, tos, pc, "cannot add to node kind: " & $u.kind)
       regs[ra].node = u
     of opcNAddMultiple:
       decodeBC(rkNode)
@@ -1233,7 +1243,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         # XXX can be optimized:
         for i in 0..<x.len: u.add(x.sons[i])
       else:
-        stackTrace(c, tos, pc, errGenerated, "cannot add to node kind: " & $u.kind)
+        stackTrace(c, tos, pc, "cannot add to node kind: " & $u.kind)
       regs[ra].node = u
     of opcNKind:
       decodeB(rkInt)
@@ -1245,34 +1255,34 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       if a.kind == nkSym:
         regs[ra].intVal = ord(a.sym.kind)
       else:
-        stackTrace(c, tos, pc, errGenerated, "node is not a symbol")
+        stackTrace(c, tos, pc, "node is not a symbol")
       c.comesFromHeuristic = regs[rb].node.info
     of opcNIntVal:
       decodeB(rkInt)
       let a = regs[rb].node
       case a.kind
       of nkCharLit..nkUInt64Lit: regs[ra].intVal = a.intVal
-      else: stackTrace(c, tos, pc, errFieldXNotFound, "intVal")
+      else: stackTrace(c, tos, pc, errFieldXNotFound & "intVal")
     of opcNFloatVal:
       decodeB(rkFloat)
       let a = regs[rb].node
       case a.kind
       of nkFloatLit..nkFloat64Lit: regs[ra].floatVal = a.floatVal
-      else: stackTrace(c, tos, pc, errFieldXNotFound, "floatVal")
+      else: stackTrace(c, tos, pc, errFieldXNotFound & "floatVal")
     of opcNSymbol:
       decodeB(rkNode)
       let a = regs[rb].node
       if a.kind == nkSym:
         regs[ra].node = copyNode(a)
       else:
-        stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
+        stackTrace(c, tos, pc, errFieldXNotFound & "symbol")
     of opcNIdent:
       decodeB(rkNode)
       let a = regs[rb].node
       if a.kind == nkIdent:
         regs[ra].node = copyNode(a)
       else:
-        stackTrace(c, tos, pc, errFieldXNotFound, "ident")
+        stackTrace(c, tos, pc, errFieldXNotFound & "ident")
     of opcNGetType:
       let rb = instr.regB
       let rc = instr.regC
@@ -1283,28 +1293,28 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
           regs[ra].node = opMapTypeToAst(regs[rb].node.typ, c.debug[pc])
         else:
-          stackTrace(c, tos, pc, errGenerated, "node has no type")
+          stackTrace(c, tos, pc, "node has no type")
       of 1:
         # typeKind opcode:
         ensureKind(rkInt)
         if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
           regs[ra].intVal = ord(regs[rb].node.typ.kind)
         #else:
-        #  stackTrace(c, tos, pc, errGenerated, "node has no type")
+        #  stackTrace(c, tos, pc, "node has no type")
       of 2:
         # getTypeInst opcode:
         ensureKind(rkNode)
         if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
           regs[ra].node = opMapTypeInstToAst(regs[rb].node.typ, c.debug[pc])
         else:
-          stackTrace(c, tos, pc, errGenerated, "node has no type")
+          stackTrace(c, tos, pc, "node has no type")
       else:
         # getTypeImpl opcode:
         ensureKind(rkNode)
         if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
           regs[ra].node = opMapTypeImplToAst(regs[rb].node.typ, c.debug[pc])
         else:
-          stackTrace(c, tos, pc, errGenerated, "node has no type")
+          stackTrace(c, tos, pc, "node has no type")
     of opcNStrVal:
       decodeB(rkNode)
       createStr regs[ra]
@@ -1319,12 +1329,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       of nkSym:
         regs[ra].node.strVal = a.sym.name.s
       else:
-        stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
+        stackTrace(c, tos, pc, errFieldXNotFound & "strVal")
     of opcSlurp:
       decodeB(rkNode)
       createStr regs[ra]
       regs[ra].node.strVal = opSlurp(regs[rb].node.strVal, c.debug[pc],
-                                     c.module)
+                                     c.module, c.config)
     of opcGorge:
       decodeBC(rkNode)
       inc pc
@@ -1333,29 +1343,30 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       createStr regs[ra]
       regs[ra].node.strVal = opGorge(regs[rb].node.strVal,
                                      regs[rc].node.strVal, regs[rd].node.strVal,
-                                     c.debug[pc])[0]
+                                     c.debug[pc], c.config)[0]
     of opcNError:
       decodeB(rkNode)
       let a = regs[ra].node
       let b = regs[rb].node
-      stackTrace(c, tos, pc, errUser, a.strVal, if b.kind == nkNilLit: nil else: b)
+      stackTrace(c, tos, pc, a.strVal, if b.kind == nkNilLit: nil else: b)
     of opcNWarning:
-      message(c.debug[pc], warnUser, regs[ra].node.strVal)
+      message(c.config, c.debug[pc], warnUser, regs[ra].node.strVal)
     of opcNHint:
-      message(c.debug[pc], hintUser, regs[ra].node.strVal)
+      message(c.config, c.debug[pc], hintUser, regs[ra].node.strVal)
     of opcParseExprToAst:
       decodeB(rkNode)
       # c.debug[pc].line.int - countLines(regs[rb].strVal) ?
       var error: string
       let ast = parseString(regs[rb].node.strVal, c.cache, c.config,
                             c.debug[pc].toFullPath, c.debug[pc].line.int,
-                            proc (info: TLineInfo; msg: TMsgKind; arg: string) =
-                              if error.isNil and msg <= msgs.errMax:
-                                error = formatMsg(info, msg, arg))
+                            proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) =
+                              if error.isNil and msg <= errMax:
+                                error = formatMsg(conf, info, msg, arg))
       if not error.isNil:
         c.errorFlag = error
       elif sonsLen(ast) != 1:
-        c.errorFlag = formatMsg(c.debug[pc], errExprExpected, "multiple statements")
+        c.errorFlag = formatMsg(c.config, c.debug[pc], errGenerated,
+          "expected expression, but got multiple statements")
       else:
         regs[ra].node = ast.sons[0]
     of opcParseStmtToAst:
@@ -1363,9 +1374,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       var error: string
       let ast = parseString(regs[rb].node.strVal, c.cache, c.config,
                             c.debug[pc].toFullPath, c.debug[pc].line.int,
-                            proc (info: TLineInfo; msg: TMsgKind; arg: string) =
-                              if error.isNil and msg <= msgs.errMax:
-                                error = formatMsg(info, msg, arg))
+                            proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) =
+                              if error.isNil and msg <= errMax:
+                                error = formatMsg(conf, info, msg, arg))
       if not error.isNil:
         c.errorFlag = error
       else:
@@ -1377,7 +1388,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcCallSite:
       ensureKind(rkNode)
       if c.callsite != nil: regs[ra].node = c.callsite
-      else: stackTrace(c, tos, pc, errFieldXNotFound, "callsite")
+      else: stackTrace(c, tos, pc, errFieldXNotFound & "callsite")
     of opcNGetFile:
       decodeB(rkNode)
       let n = regs[rb].node
@@ -1439,13 +1450,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcStrToIdent:
       decodeB(rkNode)
       if regs[rb].node.kind notin {nkStrLit..nkTripleStrLit}:
-        stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
+        stackTrace(c, tos, pc, errFieldXNotFound & "strVal")
       else:
         regs[ra].node = newNodeI(nkIdent, c.debug[pc])
         regs[ra].node.ident = getIdent(regs[rb].node.strVal)
     of opcSetType:
       if regs[ra].kind != rkNode:
-        internalError(c.debug[pc], "cannot set type")
+        internalError(c.config, c.debug[pc], "cannot set type")
       regs[ra].node.typ = c.types[instr.regBx - wordExcess]
     of opcConv:
       let rb = instr.regB
@@ -1454,9 +1465,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       inc pc
       let srctyp = c.types[c.code[pc].regBx - wordExcess]
 
-      if opConv(regs[ra], regs[rb], desttyp, srctyp):
-        stackTrace(c, tos, pc, errGenerated,
-          msgKindToString(errIllegalConvFromXtoY) % [
+      if opConv(c, regs[ra], regs[rb], desttyp, srctyp):
+        stackTrace(c, tos, pc,
+          errIllegalConvFromXtoY % [
           typeToString(srctyp), typeToString(desttyp)])
     of opcCast:
       let rb = instr.regB
@@ -1469,7 +1480,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         let dest = fficast(regs[rb], desttyp)
         asgnRef(regs[ra], dest)
       else:
-        globalError(c.debug[pc], "cannot evaluate cast")
+        globalError(c.config, c.debug[pc], "cannot evaluate cast")
     of opcNSetIntVal:
       decodeB(rkNode)
       var dest = regs[ra].node
@@ -1477,7 +1488,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
          regs[rb].kind in {rkInt}:
         dest.intVal = regs[rb].intVal
       else:
-        stackTrace(c, tos, pc, errFieldXNotFound, "intVal")
+        stackTrace(c, tos, pc, errFieldXNotFound & "intVal")
     of opcNSetFloatVal:
       decodeB(rkNode)
       var dest = regs[ra].node
@@ -1485,26 +1496,26 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
          regs[rb].kind in {rkFloat}:
         dest.floatVal = regs[rb].floatVal
       else:
-        stackTrace(c, tos, pc, errFieldXNotFound, "floatVal")
+        stackTrace(c, tos, pc, errFieldXNotFound & "floatVal")
     of opcNSetSymbol:
       decodeB(rkNode)
       var dest = regs[ra].node
       if dest.kind == nkSym and regs[rb].node.kind == nkSym:
         dest.sym = regs[rb].node.sym
       else:
-        stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
+        stackTrace(c, tos, pc, errFieldXNotFound & "symbol")
     of opcNSetIdent:
       decodeB(rkNode)
       var dest = regs[ra].node
       if dest.kind == nkIdent and regs[rb].node.kind == nkIdent:
         dest.ident = regs[rb].node.ident
       else:
-        stackTrace(c, tos, pc, errFieldXNotFound, "ident")
+        stackTrace(c, tos, pc, errFieldXNotFound & "ident")
     of opcNSetType:
       decodeB(rkNode)
       let b = regs[rb].node
-      internalAssert b.kind == nkSym and b.sym.kind == skType
-      internalAssert regs[ra].node != nil
+      internalAssert c.config, b.kind == nkSym and b.sym.kind == skType
+      internalAssert c.config, regs[ra].node != nil
       regs[ra].node.typ = b.sym.typ
     of opcNSetStrVal:
       decodeB(rkNode)
@@ -1515,12 +1526,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       elif dest.kind == nkCommentStmt and regs[rb].kind in {rkNode}:
         dest.comment = regs[rb].node.strVal
       else:
-        stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
+        stackTrace(c, tos, pc, errFieldXNotFound & "strVal")
     of opcNNewNimNode:
       decodeBC(rkNode)
       var k = regs[rb].intVal
       if k < 0 or k > ord(high(TNodeKind)):
-        internalError(c.debug[pc],
+        internalError(c.config, c.debug[pc],
           "request to create a NimNode of invalid kind")
       let cc = regs[rc].node
 
@@ -1554,7 +1565,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       let name = if regs[rc].node.strVal.len == 0: ":tmp"
                  else: regs[rc].node.strVal
       if k < 0 or k > ord(high(TSymKind)):
-        internalError(c.debug[pc], "request to create symbol of invalid kind")
+        internalError(c.config, c.debug[pc], "request to create symbol of invalid kind")
       var sym = newSym(k.TSymKind, name.getIdent, c.module.owner, c.debug[pc])
       incl(sym.flags, sfGenSym)
       regs[ra].node = newSymNode(sym)
@@ -1563,7 +1574,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       # type trait operation
       decodeB(rkNode)
       var typ = regs[rb].node.typ
-      internalAssert typ != nil
+      internalAssert c.config, typ != nil
       while typ.kind == tyTypeDesc and typ.len > 0: typ = typ.sons[0]
       createStr regs[ra]
       regs[ra].node.strVal = typ.typeToString(preferExported)
@@ -1572,14 +1583,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       let rb = instr.regB
       inc pc
       let typ = c.types[c.code[pc].regBx - wordExcess]
-      putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ))
+      putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ, c.config))
     of opcMarshalStore:
       decodeB(rkNode)
       inc pc
       let typ = c.types[c.code[pc].regBx - wordExcess]
       createStrKeepNode(regs[ra])
       if regs[ra].node.strVal.isNil: regs[ra].node.strVal = newStringOfCap(1000)
-      storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode)
+      storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode, c.config)
     of opcToNarrowInt:
       decodeBC(rkInt)
       let mask = (1'i64 shl rc) - 1 # 0xFF
@@ -1601,7 +1612,7 @@ proc execute(c: PCtx, start: int): PNode =
 proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
   if sym.kind in routineKinds:
     if sym.typ.len-1 != args.len:
-      localError(sym.info,
+      localError(c.config, sym.info,
         "NimScript: expected $# arguments, but got $#" % [
         $(sym.typ.len-1), $args.len])
     else:
@@ -1613,18 +1624,18 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
 
       # setup parameters:
       if not isEmptyType(sym.typ.sons[0]) or sym.kind == skMacro:
-        putIntoReg(tos.slots[0], getNullValue(sym.typ.sons[0], sym.info))
+        putIntoReg(tos.slots[0], getNullValue(sym.typ.sons[0], sym.info, c.config))
       # XXX We could perform some type checking here.
       for i in 1..<sym.typ.len:
         putIntoReg(tos.slots[i], args[i-1])
 
       result = rawExecute(c, start, tos).regToNode
   else:
-    localError(sym.info,
+    localError(c.config, sym.info,
       "NimScript: attempt to call non-routine: " & sym.name.s)
 
 proc evalStmt*(c: PCtx, n: PNode) =
-  let n = transformExpr(c.module, n)
+  let n = transformExpr(c.graph, c.module, n)
   let start = genStmt(c, n)
   # execute new instructions; this redundant opcEof check saves us lots
   # of allocations in 'execute':
@@ -1632,13 +1643,13 @@ proc evalStmt*(c: PCtx, n: PNode) =
     discard execute(c, start)
 
 proc evalExpr*(c: PCtx, n: PNode): PNode =
-  let n = transformExpr(c.module, n)
+  let n = transformExpr(c.graph, c.module, n)
   let start = genExpr(c, n)
   assert c.code[start].opcode != opcEof
   result = execute(c, start)
 
 proc getGlobalValue*(c: PCtx; s: PSym): PNode =
-  internalAssert s.kind in {skLet, skVar} and sfGlobal in s.flags
+  internalAssert c.config, s.kind in {skLet, skVar} and sfGlobal in s.flags
   result = c.globals.sons[s.position-1]
 
 include vmops
@@ -1649,9 +1660,9 @@ include vmops
 var
   globalCtx*: PCtx
 
-proc setupGlobalCtx(module: PSym; cache: IdentCache; config: ConfigRef) =
+proc setupGlobalCtx(module: PSym; cache: IdentCache; graph: ModuleGraph) =
   if globalCtx.isNil:
-    globalCtx = newCtx(module, cache, config)
+    globalCtx = newCtx(module, cache, graph)
     registerAdditionalOps(globalCtx)
   else:
     refresh(globalCtx, module)
@@ -1662,21 +1673,20 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
   #pushStackFrame(c, newStackFrame())
 
   # XXX produce a new 'globals' environment here:
-  setupGlobalCtx(module, cache, graph.config)
+  setupGlobalCtx(module, cache, graph)
   result = globalCtx
   when hasFFI:
     globalCtx.features = {allowFFI, allowCast}
 
-var oldErrorCount: int
-
 proc myProcess(c: PPassContext, n: PNode): PNode =
+  let c = PCtx(c)
   # don't eval errornous code:
-  if oldErrorCount == msgs.gErrorCounter:
-    evalStmt(PCtx(c), n)
+  if c.oldErrorCount == c.config.errorCounter:
+    evalStmt(c, n)
     result = emptyNode
   else:
     result = n
-  oldErrorCount = msgs.gErrorCounter
+  c.oldErrorCount = c.config.errorCounter
 
 proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode =
   myProcess(c, n)
@@ -1684,10 +1694,10 @@ proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode =
 const evalPass* = makePass(myOpen, nil, myProcess, myClose)
 
 proc evalConstExprAux(module: PSym; cache: IdentCache;
-                      config: ConfigRef; prc: PSym, n: PNode,
+                      g: ModuleGraph; prc: PSym, n: PNode,
                       mode: TEvalMode): PNode =
-  let n = transformExpr(module, n)
-  setupGlobalCtx(module, cache, config)
+  let n = transformExpr(g, module, n)
+  setupGlobalCtx(module, cache, g)
   var c = globalCtx
   let oldMode = c.mode
   defer: c.mode = oldMode
@@ -1702,17 +1712,17 @@ proc evalConstExprAux(module: PSym; cache: IdentCache;
   result = rawExecute(c, start, tos).regToNode
   if result.info.col < 0: result.info = n.info
 
-proc evalConstExpr*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode): PNode =
-  result = evalConstExprAux(module, cache, config, nil, e, emConst)
+proc evalConstExpr*(module: PSym; cache: IdentCache, g: ModuleGraph; e: PNode): PNode =
+  result = evalConstExprAux(module, cache, g, nil, e, emConst)
 
-proc evalStaticExpr*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode, prc: PSym): PNode =
-  result = evalConstExprAux(module, cache, config, prc, e, emStaticExpr)
+proc evalStaticExpr*(module: PSym; cache: IdentCache, g: ModuleGraph; e: PNode, prc: PSym): PNode =
+  result = evalConstExprAux(module, cache, g, prc, e, emStaticExpr)
 
-proc evalStaticStmt*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode, prc: PSym) =
-  discard evalConstExprAux(module, cache, config, prc, e, emStaticStmt)
+proc evalStaticStmt*(module: PSym; cache: IdentCache, g: ModuleGraph; e: PNode, prc: PSym) =
+  discard evalConstExprAux(module, cache, g, prc, e, emStaticStmt)
 
-proc setupCompileTimeVar*(module: PSym; cache: IdentCache, config: ConfigRef; n: PNode) =
-  discard evalConstExprAux(module, cache, config, nil, n, emStaticStmt)
+proc setupCompileTimeVar*(module: PSym; cache: IdentCache, g: ModuleGraph; n: PNode) =
+  discard evalConstExprAux(module, cache, g, nil, n, emStaticStmt)
 
 proc setupMacroParam(x: PNode, typ: PType): TFullReg =
   case typ.kind
@@ -1740,20 +1750,20 @@ iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) =
 const evalMacroLimit = 1000
 var evalMacroCounter: int
 
-proc evalMacroCall*(module: PSym; cache: IdentCache; config: ConfigRef;
+proc evalMacroCall*(module: PSym; cache: IdentCache; g: ModuleGraph;
                     n, nOrig: PNode, sym: PSym): PNode =
   # XXX globalError() is ugly here, but I don't know a better solution for now
   inc(evalMacroCounter)
   if evalMacroCounter > evalMacroLimit:
-    globalError(n.info, errMacroInstantiationTooNested)
+    globalError(g.config, n.info, "macro instantiation too nested")
 
   # immediate macros can bypass any type and arity checking so we check the
   # arity here too:
   if sym.typ.len > n.safeLen and sym.typ.len > 1:
-    globalError(n.info, "in call '$#' got $#, but expected $# argument(s)" % [
+    globalError(g.config, n.info, "in call '$#' got $#, but expected $# argument(s)" % [
         n.renderTree, $(n.safeLen-1), $(sym.typ.len-1)])
 
-  setupGlobalCtx(module, cache, config)
+  setupGlobalCtx(module, cache, g)
   var c = globalCtx
   c.comesFromHeuristic.line = 0'u16
 
@@ -1787,16 +1797,16 @@ proc evalMacroCall*(module: PSym; cache: IdentCache; config: ConfigRef;
       else:
         dec(evalMacroCounter)
         c.callsite = nil
-        localError(n.info, "expected " & $gp.len &
+        localError(c.config, n.info, "expected " & $gp.len &
                    " generic parameter(s)")
     elif gp[i].sym.typ.kind in {tyStatic, tyTypeDesc}:
       dec(evalMacroCounter)
       c.callsite = nil
-      globalError(n.info, "static[T] or typedesc nor supported for .immediate macros")
+      globalError(c.config, n.info, "static[T] or typedesc nor supported for .immediate macros")
   # temporary storage:
   #for i in L ..< maxSlots: tos.slots[i] = newNode(nkEmpty)
   result = rawExecute(c, start, tos).regToNode
   if result.info.line < 0: result.info = n.info
-  if cyclicTree(result): globalError(n.info, errCyclicTree)
+  if cyclicTree(result): globalError(c.config, n.info, "macro produced a cyclic tree")
   dec(evalMacroCounter)
   c.callsite = nil
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index b0a559d2c..e10a62006 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -10,7 +10,7 @@
 ## This module contains the type definitions for the new evaluation engine.
 ## An instruction is 1-3 int32s in memory, it is a register based VM.
 
-import ast, passes, msgs, idents, intsets, options
+import ast, passes, msgs, idents, intsets, options, modulegraphs
 
 const
   byteExcess* = 128 # we use excess-K for immediates
@@ -207,18 +207,19 @@ type
     errorFlag*: string
     cache*: IdentCache
     config*: ConfigRef
+    graph*: ModuleGraph
+    oldErrorCount*: int
 
   TPosition* = distinct int
 
   PEvalContext* = PCtx
 
-proc newCtx*(module: PSym; cache: IdentCache; config: ConfigRef = nil): PCtx =
-  let conf = if config != nil: config else: newConfigRef()
+proc newCtx*(module: PSym; cache: IdentCache; g: ModuleGraph): PCtx =
   PCtx(code: @[], debug: @[],
     globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
     prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations,
     comesFromHeuristic: unknownLineInfo(), callbacks: @[], errorFlag: "",
-    cache: cache, config: conf)
+    cache: cache, config: g.config, graph: g)
 
 proc refresh*(c: PCtx, module: PSym) =
   c.module = module
diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim
index ba37237e8..2c92348a6 100644
--- a/compiler/vmdeps.nim
+++ b/compiler/vmdeps.nim
@@ -9,18 +9,18 @@
 
 import ast, types, msgs, os, streams, options, idents
 
-proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
+proc opSlurp*(file: string, info: TLineInfo, module: PSym; conf: ConfigRef): string =
   try:
     var filename = parentDir(info.toFullPath) / file
     if not fileExists(filename):
-      filename = file.findFile
+      filename = findFile(conf, file)
     result = readFile(filename)
     # we produce a fake include statement for every slurped filename, so that
     # the module dependencies are accurate:
     appendToModule(module, newNode(nkIncludeStmt, info, @[
       newStrNode(nkStrLit, filename)]))
   except IOError:
-    localError(info, errCannotOpenFile, file)
+    localError(conf, info, "cannot open file: " & file)
     result = ""
 
 proc atomicTypeX(name: string; m: TMagic; t: PType; info: TLineInfo): PNode =
@@ -271,7 +271,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
   of tyOr: result = mapTypeToBracket("or", mOr, t, info)
   of tyNot: result = mapTypeToBracket("not", mNot, t, info)
   of tyAnything: result = atomicType("anything", mNone)
-  of tyInferred: internalAssert false
+  of tyInferred: assert false
   of tyStatic, tyFromExpr:
     if inst:
       if t.n != nil: result = t.n.copyTree
@@ -281,7 +281,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
       result.add atomicType("static", mNone)
       if t.n != nil:
         result.add t.n.copyTree
-  of tyUnused, tyOptAsRef: internalError("mapTypeToAstX")
+  of tyUnused, tyOptAsRef: assert(false, "mapTypeToAstX")
 
 proc opMapTypeToAst*(t: PType; info: TLineInfo): PNode =
   result = mapTypeToAstX(t, info, false, true)
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 7f91e63db..7ac3b5cf7 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -120,7 +120,7 @@ proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) =
     c.code.add(ins)
     c.debug.add(n.info)
   else:
-    localError(n.info, errGenerated,
+    localError(c.config, n.info,
       "VM: immediate value does not fit into an int8")
 
 proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) =
@@ -137,7 +137,7 @@ proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) =
     c.code.add(ins)
     c.debug.add(n.info)
   else:
-    localError(n.info, errGenerated,
+    localError(c.config, n.info,
       "VM: immediate value does not fit into an int16")
 
 proc xjmp(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0): TPosition =
@@ -151,7 +151,7 @@ proc genLabel(c: PCtx): TPosition =
 
 proc jmpBack(c: PCtx, n: PNode, p = TPosition(0)) =
   let dist = p.int - c.code.len
-  internalAssert(-0x7fff < dist and dist < 0x7fff)
+  internalAssert(c.config, -0x7fff < dist and dist < 0x7fff)
   gABx(c, n, opcJmpBack, 0, dist)
 
 proc patch(c: PCtx, p: TPosition) =
@@ -159,7 +159,7 @@ proc patch(c: PCtx, p: TPosition) =
   let p = p.int
   let diff = c.code.len - p
   #c.jumpTargets.incl(c.code.len)
-  internalAssert(-0x7fff < diff and diff < 0x7fff)
+  internalAssert(c.config, -0x7fff < diff and diff < 0x7fff)
   let oldInstr = c.code[p]
   # opcode and regA stay the same:
   c.code[p] = ((oldInstr.uint32 and 0xffff'u32).uint32 or
@@ -201,7 +201,7 @@ proc getTemp(cc: PCtx; tt: PType): TRegister =
         c.slots[i] = (inUse: true, kind: k)
         return TRegister(i)
   if c.maxSlots >= high(TRegister):
-    globalError(cc.bestEffort, "VM problem: too many registers required")
+    globalError(cc.config, cc.bestEffort, "VM problem: too many registers required")
   result = TRegister(c.maxSlots)
   c.slots[c.maxSlots] = (inUse: true, kind: k)
   inc c.maxSlots
@@ -223,7 +223,7 @@ proc getTempRange(cc: PCtx; n: int; kind: TSlotKind): TRegister =
           for k in result .. result+n-1: c.slots[k] = (inUse: true, kind: kind)
           return
   if c.maxSlots+n >= high(TRegister):
-    globalError(cc.bestEffort, "VM problem: too many registers required")
+    globalError(cc.config, cc.bestEffort, "VM problem: too many registers required")
   result = TRegister(c.maxSlots)
   inc c.maxSlots, n
   for k in result .. result+n-1: c.slots[k] = (inUse: true, kind: kind)
@@ -251,7 +251,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {})
 proc gen(c: PCtx; n: PNode; dest: TRegister; flags: TGenFlags = {}) =
   var d: TDest = dest
   gen(c, n, d, flags)
-  #internalAssert d == dest # issue #7407
+  #internalAssert c.config, d == dest # issue #7407
 
 proc gen(c: PCtx; n: PNode; flags: TGenFlags = {}) =
   var tmp: TDest = -1
@@ -261,7 +261,7 @@ proc gen(c: PCtx; n: PNode; flags: TGenFlags = {}) =
 proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister =
   var tmp: TDest = -1
   gen(c, n, tmp, flags)
-  #internalAssert tmp >= 0 # 'nim check' does not like this internalAssert.
+  #internalAssert c.config, tmp >= 0 # 'nim check' does not like this internalAssert.
   if tmp >= 0:
     result = TRegister(tmp)
 
@@ -320,7 +320,7 @@ proc genBreak(c: PCtx; n: PNode) =
       if c.prc.blocks[i].label == n.sons[0].sym:
         c.prc.blocks[i].fixups.add L1
         return
-    globalError(n.info, errGenerated, "VM problem: cannot find 'break' target")
+    globalError(c.config, n.info, "VM problem: cannot find 'break' target")
   else:
     c.prc.blocks[c.prc.blocks.high].fixups.add L1
 
@@ -378,7 +378,7 @@ proc rawGenLiteral(c: PCtx; n: PNode): int =
   #assert(n.kind != nkCall)
   n.flags.incl nfAllConst
   c.constants.add n.canonValue
-  internalAssert result < 0x7fff
+  internalAssert c.config, result < 0x7fff
 
 proc sameConstant*(a, b: PNode): bool =
   result = false
@@ -405,10 +405,10 @@ proc genLiteral(c: PCtx; n: PNode): int =
     if sameConstant(c.constants[i], n): return i
   result = rawGenLiteral(c, n)
 
-proc unused(n: PNode; x: TDest) {.inline.} =
+proc unused(c: PCtx; n: PNode; x: TDest) {.inline.} =
   if x >= 0:
     #debug(n)
-    globalError(n.info, "not unused")
+    globalError(c.config, n.info, "not unused")
 
 proc genCase(c: PCtx; n: PNode; dest: var TDest) =
   #  if (!expr1) goto L1;
@@ -424,7 +424,7 @@ proc genCase(c: PCtx; n: PNode; dest: var TDest) =
   if not isEmptyType(n.typ):
     if dest < 0: dest = getTemp(c, n.typ)
   else:
-    unused(n, dest)
+    unused(c, n, dest)
   var endings: seq[TPosition] = @[]
   withTemp(tmp, n.sons[0].typ):
     c.gen(n.sons[0], tmp)
@@ -451,7 +451,7 @@ proc genType(c: PCtx; typ: PType): int =
     if sameType(t, typ): return i
   result = c.types.len
   c.types.add(typ)
-  internalAssert(result <= 0x7fff)
+  internalAssert(c.config, result <= 0x7fff)
 
 proc genTry(c: PCtx; n: PNode; dest: var TDest) =
   if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
@@ -525,7 +525,7 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) =
     var r: TRegister = x+i
     c.gen(n.sons[i], r)
     if i >= fntyp.len:
-      internalAssert tfVarargs in fntyp.flags
+      internalAssert c.config, tfVarargs in fntyp.flags
       c.gABx(n, opcSetType, r, c.genType(n.sons[i].typ))
   if dest < 0:
     c.gABC(n, opcIndCall, 0, x, n.len)
@@ -540,12 +540,12 @@ proc needsAsgnPatch(n: PNode): bool =
   n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr,
              nkDerefExpr, nkHiddenDeref} or (n.kind == nkSym and n.sym.isGlobal)
 
-proc genField(n: PNode): TRegister =
+proc genField(c: PCtx; n: PNode): TRegister =
   if n.kind != nkSym or n.sym.kind != skField:
-    globalError(n.info, "no field symbol")
+    globalError(c.config, n.info, "no field symbol")
   let s = n.sym
   if s.position > high(result):
-    globalError(n.info,
+    globalError(c.config, n.info,
         "too large offset! cannot generate code for: " & s.name.s)
   result = s.position
 
@@ -572,7 +572,7 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
     # XXX field checks here
     let left = if le.kind == nkDotExpr: le else: le.sons[0]
     let dest = c.genx(left.sons[0], {gfAddrOf, gfFieldAccess})
-    let idx = genField(left.sons[1])
+    let idx = genField(c, left.sons[1])
     c.gABC(left, opcWrObj, dest, idx, value)
     c.freeTemp(dest)
   of nkDerefExpr, nkHiddenDeref:
@@ -779,7 +779,7 @@ proc genIntCast(c: PCtx; n: PNode; dest: var TDest) =
     let tmp3 = c.getTemp(n.sons[1].typ)
     if dest < 0: dest = c.getTemp(n[0].typ)
     proc mkIntLit(ival: int): int =
-      result = genLiteral(c, newIntTypeNode(nkIntLit, ival, getSysType(tyInt)))
+      result = genLiteral(c, newIntTypeNode(nkIntLit, ival, getSysType(c.graph, n.info, tyInt)))
     if src.kind in unsignedIntegers and dst.kind in signedIntegers:
       # cast unsigned to signed integer of same size
       # signedVal = (unsignedVal xor offset) -% offset
@@ -802,7 +802,7 @@ proc genIntCast(c: PCtx; n: PNode; dest: var TDest) =
     c.freeTemp(tmp2)
     c.freeTemp(tmp3)
   else:
-    globalError(n.info, errGenerated, "VM is only allowed to 'cast' between integers of same size")
+    globalError(c.config, n.info, "VM is only allowed to 'cast' between integers of same size")
 
 proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   case m
@@ -818,7 +818,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mSucc, mAddI:
     c.genAddSubInt(n, dest, opcAddInt)
   of mInc, mDec:
-    unused(n, dest)
+    unused(c, n, dest)
     let opc = if m == mInc: opcAddInt else: opcSubInt
     let d = c.genx(n.sons[1])
     if n.sons[2].isInt8Lit:
@@ -832,10 +832,10 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     c.freeTemp(d)
   of mOrd, mChr, mArrToSeq: c.gen(n.sons[1], dest)
   of mNew, mNewFinalize:
-    unused(n, dest)
+    unused(c, n, dest)
     c.genNew(n)
   of mNewSeq:
-    unused(n, dest)
+    unused(c, n, dest)
     c.genNewSeq(n)
   of mNewSeqOfCap: c.genNewSeqOfCap(n, dest)
   of mNewString:
@@ -855,7 +855,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mLengthStr, mXLenStr:
     genUnaryABI(c, n, dest, opcLenStr)
   of mIncl, mExcl:
-    unused(n, dest)
+    unused(c, n, dest)
     var d = c.genx(n.sons[1])
     var tmp = c.genx(n.sons[2])
     c.genSetType(n.sons[1], d)
@@ -952,19 +952,19 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mInSet: genBinarySet(c, n, dest, opcContainsSet)
   of mRepr: genUnaryABC(c, n, dest, opcRepr)
   of mExit:
-    unused(n, dest)
+    unused(c, n, dest)
     var tmp = c.genx(n.sons[1])
     c.gABC(n, opcQuit, tmp)
     c.freeTemp(tmp)
   of mSetLengthStr, mSetLengthSeq:
-    unused(n, dest)
+    unused(c, n, dest)
     var d = c.genx(n.sons[1])
     var tmp = c.genx(n.sons[2])
     c.gABC(n, if m == mSetLengthStr: opcSetLenStr else: opcSetLenSeq, d, tmp)
     c.genAsgnPatch(n.sons[1], d)
     c.freeTemp(tmp)
   of mSwap:
-    unused(n, dest)
+    unused(c, n, dest)
     c.gen(lowerSwap(n, if c.prc == nil: c.module else: c.prc.sym))
   of mIsNil: genUnaryABC(c, n, dest, opcIsNil)
   of mCopyStr:
@@ -996,7 +996,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     # skip 'nkHiddenAddr':
     let d2AsNode = n.sons[2].sons[0]
     if needsAsgnPatch(d2AsNode):
-      d2 = c.getTemp(getSysType(tyFloat))
+      d2 = c.getTemp(getSysType(c.graph, n.info, tyFloat))
     else:
       d2 = c.genx(d2AsNode)
     var
@@ -1009,13 +1009,13 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     c.genAsgnPatch(d2AsNode, d2)
     c.freeTemp(d2)
   of mReset:
-    unused(n, dest)
+    unused(c, n, dest)
     var d = c.genx(n.sons[1])
     c.gABC(n, opcReset, d)
   of mOf, mIs:
     if dest < 0: dest = c.getTemp(n.typ)
     var tmp = c.genx(n.sons[1])
-    var idx = c.getTemp(getSysType(tyInt))
+    var idx = c.getTemp(getSysType(c.graph, n.info, tyInt))
     var typ = n.sons[2].typ
     if m == mOf: typ = typ.skipTypes(abstractPtrs-{tyTypeDesc})
     c.gABx(n, opcLdImmInt, idx, c.genType(typ))
@@ -1023,7 +1023,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     c.freeTemp(tmp)
     c.freeTemp(idx)
   of mSizeOf:
-    globalError(n.info, errCannotInterpretNodeX, renderTree(n))
+    globalError(c.config, n.info, "cannot run in the VM: " & renderTree(n))
   of mHigh:
     if dest < 0: dest = c.getTemp(n.typ)
     let tmp = c.genx(n.sons[1])
@@ -1034,23 +1034,23 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
       c.gABI(n, opcLenSeq, dest, tmp, 1)
     c.freeTemp(tmp)
   of mEcho:
-    unused(n, dest)
+    unused(c, n, dest)
     let n = n[1].skipConv
     let x = c.getTempRange(n.len, slotTempUnknown)
-    internalAssert n.kind == nkBracket
+    internalAssert c.config, n.kind == nkBracket
     for i in 0..<n.len:
       var r: TRegister = x+i
       c.gen(n.sons[i], r)
     c.gABC(n, opcEcho, x, n.len)
     c.freeTempRange(x, n.len)
   of mAppendStrCh:
-    unused(n, dest)
+    unused(c, n, dest)
     genBinaryStmtVar(c, n, opcAddStrCh)
   of mAppendStrStr:
-    unused(n, dest)
+    unused(c, n, dest)
     genBinaryStmtVar(c, n, opcAddStrStr)
   of mAppendSeqElem:
-    unused(n, dest)
+    unused(c, n, dest)
     genBinaryStmtVar(c, n, opcAddSeqElem)
   of mParseExprToAst:
     genUnaryABC(c, n, dest, opcParseExprToAst)
@@ -1068,7 +1068,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mGetImpl: genUnaryABC(c, n, dest, opcGetImpl)
   of mNChild: genBinaryABC(c, n, dest, opcNChild)
   of mNSetChild, mNDel:
-    unused(n, dest)
+    unused(c, n, dest)
     var
       tmp1 = c.genx(n.sons[1])
       tmp2 = c.genx(n.sons[2])
@@ -1098,22 +1098,22 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     #genUnaryABC(c, n, dest, opcNGetType)
   of mNStrVal: genUnaryABC(c, n, dest, opcNStrVal)
   of mNSetIntVal:
-    unused(n, dest)
+    unused(c, n, dest)
     genBinaryStmt(c, n, opcNSetIntVal)
   of mNSetFloatVal:
-    unused(n, dest)
+    unused(c, n, dest)
     genBinaryStmt(c, n, opcNSetFloatVal)
   of mNSetSymbol:
-    unused(n, dest)
+    unused(c, n, dest)
     genBinaryStmt(c, n, opcNSetSymbol)
   of mNSetIdent:
-    unused(n, dest)
+    unused(c, n, dest)
     genBinaryStmt(c, n, opcNSetIdent)
   of mNSetType:
-    unused(n, dest)
+    unused(c, n, dest)
     genBinaryStmt(c, n, opcNSetType)
   of mNSetStrVal:
-    unused(n, dest)
+    unused(c, n, dest)
     genBinaryStmt(c, n, opcNSetStrVal)
   of mNNewNimNode: genBinaryABC(c, n, dest, opcNNewNimNode)
   of mNCopyNimNode: genUnaryABC(c, n, dest, opcNCopyNimNode)
@@ -1124,7 +1124,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
       if dest < 0: dest = c.getTemp(n.typ)
       c.gABx(n, opcNBindSym, dest, idx)
     else:
-      localError(n.info, "invalid bindSym usage")
+      localError(c.config, n.info, "invalid bindSym usage")
   of mStrToIdent: genUnaryABC(c, n, dest, opcStrToIdent)
   of mEqIdent: genBinaryABC(c, n, dest, opcEqIdent)
   of mEqNimrodNode: genBinaryABC(c, n, dest, opcEqNimrodNode)
@@ -1138,12 +1138,12 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     of "getColumn":
       genUnaryABC(c, n, dest, opcNGetColumn)
     else:
-      internalAssert false
+      internalAssert c.config, false
   of mNHint:
-    unused(n, dest)
+    unused(c, n, dest)
     genUnaryStmt(c, n, opcNHint)
   of mNWarning:
-    unused(n, dest)
+    unused(c, n, dest)
     genUnaryStmt(c, n, opcNWarning)
   of mNError:
     if n.len <= 1:
@@ -1151,7 +1151,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
       c.gABC(n, opcQueryErrorFlag, dest)
     else:
       # setter
-      unused(n, dest)
+      unused(c, n, dest)
       genBinaryStmt(c, n, opcNError)
   of mNCallSite:
     if dest < 0: dest = c.getTemp(n.typ)
@@ -1162,7 +1162,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     c.genCall(n, dest)
   of mExpandToAst:
     if n.len != 2:
-      globalError(n.info, errGenerated, "expandToAst requires 1 argument")
+      globalError(c.config, n.info, "expandToAst requires 1 argument")
     let arg = n.sons[1]
     if arg.kind in nkCallKinds:
       #if arg[0].kind != nkSym or arg[0].sym.kind notin {skTemplate, skMacro}:
@@ -1172,12 +1172,12 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
       # do not call clearDest(n, dest) here as getAst has a meta-type as such
       # produces a value
     else:
-      globalError(n.info, "expandToAst requires a call expression")
+      globalError(c.config, n.info, "expandToAst requires a call expression")
   of mRunnableExamples:
     discard "just ignore any call to runnableExamples"
   else:
     # mGCref, mGCunref,
-    globalError(n.info, "cannot generate code for: " & $m)
+    globalError(c.config, n.info, "cannot generate code for: " & $m)
 
 proc genMarshalLoad(c: PCtx, n: PNode, dest: var TDest) =
   ## Signature: proc to*[T](data: string): T
@@ -1306,14 +1306,14 @@ proc setSlot(c: PCtx; v: PSym) =
   if v.position == 0:
     if c.prc.maxSlots == 0: c.prc.maxSlots = 1
     if c.prc.maxSlots >= high(TRegister):
-      globalError(v.info, "cannot generate code; too many registers required")
+      globalError(c.config, v.info, "cannot generate code; too many registers required")
     v.position = c.prc.maxSlots
     c.prc.slots[v.position] = (inUse: true,
         kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
     inc c.prc.maxSlots
 
-proc cannotEval(n: PNode) {.noinline.} =
-  globalError(n.info, errGenerated, "cannot evaluate at compile time: " &
+proc cannotEval(c: PCtx; n: PNode) {.noinline.} =
+  globalError(c.config, n.info, "cannot evaluate at compile time: " &
     n.renderTree)
 
 proc isOwnedBy(a, b: PSym): bool =
@@ -1333,10 +1333,10 @@ proc checkCanEval(c: PCtx; n: PNode) =
   if {sfCompileTime, sfGlobal} <= s.flags: return
   if s.kind in {skVar, skTemp, skLet, skParam, skResult} and
       not s.isOwnedBy(c.prc.sym) and s.owner != c.module and c.mode != emRepl:
-    cannotEval(n)
+    cannotEval(c, n)
   elif s.kind in {skProc, skFunc, skConverter, skMethod,
                   skIterator} and sfForward in s.flags:
-    cannotEval(n)
+    cannotEval(c, n)
 
 proc isTemp(c: PCtx; dest: TDest): bool =
   result = dest >= 0 and c.prc.slots[dest].kind >= slotTempUnknown
@@ -1378,7 +1378,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
     # XXX field checks here
     let left = if le.kind == nkDotExpr: le else: le.sons[0]
     let dest = c.genx(left.sons[0], {gfAddrOf, gfFieldAccess})
-    let idx = genField(left.sons[1])
+    let idx = genField(c, left.sons[1])
     let tmp = c.genx(ri)
     c.preventFalseAlias(left, opcWrObj, dest, idx, tmp)
     c.freeTemp(tmp)
@@ -1398,7 +1398,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
         c.freeTemp(val)
     else:
       if s.kind == skForVar: c.setSlot s
-      internalAssert s.position > 0 or (s.position == 0 and
+      internalAssert c.config, s.position > 0 or (s.position == 0 and
                                         s.kind in {skParam,skResult})
       var dest: TRegister = s.position + ord(s.kind == skParam)
       assert le.typ != nil
@@ -1424,15 +1424,15 @@ proc importcSym(c: PCtx; info: TLineInfo; s: PSym) =
       c.globals.add(importcSymbol(s))
       s.position = c.globals.len
     else:
-      localError(info, errGenerated, "VM is not allowed to 'importc'")
+      localError(c.config, info, "VM is not allowed to 'importc'")
   else:
-    localError(info, errGenerated,
+    localError(c.config, info,
                "cannot 'importc' variable at compile time")
 
-proc getNullValue*(typ: PType, info: TLineInfo): PNode
+proc getNullValue*(typ: PType, info: TLineInfo; conf: ConfigRef): PNode
 
 proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
-  c.globals.add(getNullValue(s.typ, n.info))
+  c.globals.add(getNullValue(s.typ, n.info, c.config))
   s.position = c.globals.len
   # This is rather hard to support, due to the laziness of the VM code
   # generator. See tests/compile/tmacro2 for why this is necessary:
@@ -1451,7 +1451,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
     if sfCompileTime in s.flags or c.mode == emRepl:
       discard
     elif s.position == 0:
-      cannotEval(n)
+      cannotEval(c, n)
     if s.position == 0:
       if sfImportc in s.flags: c.importcSym(n.info, s)
       else: genGlobalInit(c, n, s)
@@ -1472,13 +1472,13 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
                           s.kind in {skParam,skResult}):
       if dest < 0:
         dest = s.position + ord(s.kind == skParam)
-        internalAssert(c.prc.slots[dest].kind < slotSomeTemp)
+        internalAssert(c.config, c.prc.slots[dest].kind < slotSomeTemp)
       else:
         # we need to generate an assignment:
         genAsgn(c, dest, n, c.prc.slots[dest].kind >= slotSomeTemp)
     else:
       # see tests/t99bott for an example that triggers it:
-      cannotEval(n)
+      cannotEval(c, n)
 
 template needsRegLoad(): untyped =
   gfAddrOf notin flags and fitsRegister(n.typ.skipTypes({tyVar, tyLent}))
@@ -1502,7 +1502,7 @@ proc genArrAccess2(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
 
 proc genObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
   let a = c.genx(n.sons[0], flags)
-  let b = genField(n.sons[1])
+  let b = genField(c, n.sons[1])
   if dest < 0: dest = c.getTemp(n.typ)
   if needsRegLoad():
     var cc = c.getTemp(n.typ)
@@ -1526,22 +1526,22 @@ proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
   else:
     genArrAccess2(c, n, dest, opcLdArr, flags)
 
-proc getNullValueAux(obj: PNode, result: PNode) =
+proc getNullValueAux(obj: PNode, result: PNode; conf: ConfigRef) =
   case obj.kind
   of nkRecList:
-    for i in countup(0, sonsLen(obj) - 1): getNullValueAux(obj.sons[i], result)
+    for i in countup(0, sonsLen(obj) - 1): getNullValueAux(obj.sons[i], result, conf)
   of nkRecCase:
-    getNullValueAux(obj.sons[0], result)
+    getNullValueAux(obj.sons[0], result, conf)
     for i in countup(1, sonsLen(obj) - 1):
-      getNullValueAux(lastSon(obj.sons[i]), result)
+      getNullValueAux(lastSon(obj.sons[i]), result, conf)
   of nkSym:
     let field = newNodeI(nkExprColonExpr, result.info)
     field.add(obj)
-    field.add(getNullValue(obj.sym.typ, result.info))
+    field.add(getNullValue(obj.sym.typ, result.info, conf))
     addSon(result, field)
-  else: globalError(result.info, "cannot create null element for: " & $obj)
+  else: globalError(conf, result.info, "cannot create null element for: " & $obj)
 
-proc getNullValue(typ: PType, info: TLineInfo): PNode =
+proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode =
   var t = skipTypes(typ, abstractRange-{tyTypeDesc})
   result = emptyNode
   case t.kind
@@ -1570,17 +1570,17 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
     # initialize inherited fields:
     var base = t.sons[0]
     while base != nil:
-      getNullValueAux(skipTypes(base, skipPtrs).n, result)
+      getNullValueAux(skipTypes(base, skipPtrs).n, result, conf)
       base = base.sons[0]
-    getNullValueAux(t.n, result)
+    getNullValueAux(t.n, result, conf)
   of tyArray:
     result = newNodeIT(nkBracket, info, t)
     for i in countup(0, int(lengthOrd(t)) - 1):
-      addSon(result, getNullValue(elemType(t), info))
+      addSon(result, getNullValue(elemType(t), info, conf))
   of tyTuple:
     result = newNodeIT(nkTupleConstr, info, t)
     for i in countup(0, sonsLen(t) - 1):
-      addSon(result, getNullValue(t.sons[i], info))
+      addSon(result, getNullValue(t.sons[i], info, conf))
   of tySet:
     result = newNodeIT(nkCurly, info, t)
   of tyOpt:
@@ -1588,7 +1588,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
   of tySequence:
     result = newNodeIT(nkBracket, info, t)
   else:
-    globalError(info, "cannot create null element for: " & $t.kind)
+    globalError(conf, info, "cannot create null element for: " & $t.kind)
 
 proc ldNullOpcode(t: PType): TOpcode =
   assert t != nil
@@ -1602,7 +1602,7 @@ proc genVarSection(c: PCtx; n: PNode) =
       for i in 0 .. a.len-3:
         if not a[i].sym.isGlobal: setSlot(c, a[i].sym)
         checkCanEval(c, a[i])
-      c.gen(lowerTupleUnpacking(a, c.getOwner))
+      c.gen(lowerTupleUnpacking(c.graph, a, c.getOwner))
     elif a.sons[0].kind == nkSym:
       let s = a.sons[0].sym
       checkCanEval(c, a.sons[0])
@@ -1610,7 +1610,7 @@ proc genVarSection(c: PCtx; n: PNode) =
         if s.position == 0:
           if sfImportc in s.flags: c.importcSym(a.info, s)
           else:
-            let sa = getNullValue(s.typ, a.info)
+            let sa = getNullValue(s.typ, a.info, c.config)
             #if s.ast.isNil: getNullValue(s.typ, a.info)
             #else: canonValue(s.ast)
             assert sa.kind != nkCall
@@ -1652,7 +1652,7 @@ proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) =
   if dest < 0: dest = c.getTemp(n.typ)
   c.gABx(n, opcLdNull, dest, c.genType(n.typ))
 
-  let intType = getSysType(tyInt)
+  let intType = getSysType(c.graph, n.info, tyInt)
   let seqType = n.typ.skipTypes(abstractVar-{tyTypeDesc})
   if seqType.kind == tySequence:
     var tmp = c.getTemp(intType)
@@ -1696,13 +1696,13 @@ proc genObjConstr(c: PCtx, n: PNode, dest: var TDest) =
   for i in 1..<n.len:
     let it = n.sons[i]
     if it.kind == nkExprColonExpr and it.sons[0].kind == nkSym:
-      let idx = genField(it.sons[0])
+      let idx = genField(c, it.sons[0])
       let tmp = c.genx(it.sons[1])
       c.preventFalseAlias(it.sons[1], whichAsgnOpc(it.sons[1], opcWrObj),
                           dest, idx, tmp)
       c.freeTemp(tmp)
     else:
-      globalError(n.info, "invalid object constructor")
+      globalError(c.config, n.info, "invalid object constructor")
 
 proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
   if dest < 0: dest = c.getTemp(n.typ)
@@ -1711,7 +1711,7 @@ proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
   for i in 0..<n.len:
     let it = n.sons[i]
     if it.kind == nkExprColonExpr:
-      let idx = genField(it.sons[0])
+      let idx = genField(c, it.sons[0])
       let tmp = c.genx(it.sons[1])
       c.preventFalseAlias(it.sons[1], whichAsgnOpc(it.sons[1], opcWrObj),
                           dest, idx, tmp)
@@ -1786,9 +1786,9 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
       if c.prc.sym != nil and c.prc.sym.kind == skMacro:
         genRdVar(c, n, dest, flags)
       else:
-        globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
+        globalError(c.config, n.info, "cannot generate code for: " & s.name.s)
     else:
-      globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
+      globalError(c.config, n.info, "cannot generate code for: " & s.name.s)
   of nkCallKinds:
     if n.sons[0].kind == nkSym:
       let s = n.sons[0].sym
@@ -1812,10 +1812,10 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
       genLit(c, n, dest)
   of nkUIntLit..pred(nkNilLit): genLit(c, n, dest)
   of nkNilLit:
-    if not n.typ.isEmptyType: genLit(c, getNullValue(n.typ, n.info), dest)
-    else: unused(n, dest)
+    if not n.typ.isEmptyType: genLit(c, getNullValue(n.typ, n.info, c.config), dest)
+    else: unused(c, n, dest)
   of nkAsgn, nkFastAsgn:
-    unused(n, dest)
+    unused(c, n, dest)
     genAsgn(c, n.sons[0], n.sons[1], n.kind == nkAsgn)
   of nkDotExpr: genObjAccess(c, n, dest, flags)
   of nkCheckedFieldExpr: genCheckedObjAccess(c, n, dest, flags)
@@ -1828,20 +1828,20 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     gen(c, n.sons[0].sons[1], dest)
   of nkCaseStmt: genCase(c, n, dest)
   of nkWhileStmt:
-    unused(n, dest)
+    unused(c, n, dest)
     genWhile(c, n)
   of nkBlockExpr, nkBlockStmt: genBlock(c, n, dest)
   of nkReturnStmt:
-    unused(n, dest)
+    unused(c, n, dest)
     genReturn(c, n)
   of nkRaiseStmt:
     genRaise(c, n)
   of nkBreakStmt:
-    unused(n, dest)
+    unused(c, n, dest)
     genBreak(c, n)
   of nkTryStmt: genTry(c, n, dest)
   of nkStmtList:
-    #unused(n, dest)
+    #unused(c, n, dest)
     # XXX Fix this bug properly, lexim triggers it
     for x in n: gen(c, x)
   of nkStmtListExpr:
@@ -1851,17 +1851,17 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
   of nkPragmaBlock:
     gen(c, n.lastSon, dest, flags)
   of nkDiscardStmt:
-    unused(n, dest)
+    unused(c, n, dest)
     gen(c, n.sons[0])
   of nkHiddenStdConv, nkHiddenSubConv, nkConv:
     genConv(c, n, n.sons[1], dest)
   of nkObjDownConv:
     genConv(c, n, n.sons[0], dest)
   of nkVarSection, nkLetSection:
-    unused(n, dest)
+    unused(c, n, dest)
     genVarSection(c, n)
   of declarativeDefs, nkMacroDef:
-    unused(n, dest)
+    unused(c, n, dest)
   of nkLambdaKinds:
     #let s = n.sons[namePos].sym
     #discard genProc(c, s)
@@ -1881,7 +1881,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
       dest = tmp0
   of nkEmpty, nkCommentStmt, nkTypeSection, nkConstSection, nkPragma,
      nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt:
-    unused(n, dest)
+    unused(c, n, dest)
   of nkStringToCString, nkCStringToString:
     gen(c, n.sons[0], dest)
   of nkBracket: genArrayConstr(c, n, dest)
@@ -1898,7 +1898,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
   of nkComesFrom:
     discard "XXX to implement for better stack traces"
   else:
-    globalError(n.info, errGenerated, "cannot generate VM code for " & $n)
+    globalError(c.config, n.info, "cannot generate VM code for " & $n)
 
 proc removeLastEof(c: PCtx) =
   let last = c.code.len-1
@@ -1915,7 +1915,7 @@ proc genStmt*(c: PCtx; n: PNode): int =
   c.gen(n, d)
   c.gABC(n, opcEof)
   if d >= 0:
-    globalError(n.info, errGenerated, "VM problem: dest register is set")
+    globalError(c.config, n.info, "VM problem: dest register is set")
 
 proc genExpr*(c: PCtx; n: PNode, requiresValue = true): int =
   c.removeLastEof
@@ -1924,7 +1924,7 @@ proc genExpr*(c: PCtx; n: PNode, requiresValue = true): int =
   c.gen(n, d)
   if d < 0:
     if requiresValue:
-      globalError(n.info, errGenerated, "VM problem: dest register is not set")
+      globalError(c.config, n.info, "VM problem: dest register is not set")
     d = 0
   c.gABC(n, opcEof, d)
 
@@ -1939,7 +1939,7 @@ proc genParams(c: PCtx; params: PNode) =
   c.prc.maxSlots = max(params.len, 1)
 
 proc finalJumpTarget(c: PCtx; pc, diff: int) =
-  internalAssert(-0x7fff < diff and diff < 0x7fff)
+  internalAssert(c.config, -0x7fff < diff and diff < 0x7fff)
   let oldInstr = c.code[pc]
   # opcode and regA stay the same:
   c.code[pc] = ((oldInstr.uint32 and 0xffff'u32).uint32 or
diff --git a/compiler/vmmarshal.nim b/compiler/vmmarshal.nim
index d76909443..f38be7c29 100644
--- a/compiler/vmmarshal.nim
+++ b/compiler/vmmarshal.nim
@@ -9,7 +9,8 @@
 
 ## Implements marshaling for the VM.
 
-import streams, json, intsets, tables, ast, astalgo, idents, types, msgs
+import streams, json, intsets, tables, ast, astalgo, idents, types, msgs,
+  options
 
 proc ptrToInt(x: PNode): int {.inline.} =
   result = cast[int](x) # don't skip alignment
@@ -28,37 +29,38 @@ proc getField(n: PNode; position: int): PSym =
       of nkOfBranch, nkElse:
         result = getField(lastSon(n.sons[i]), position)
         if result != nil: return
-      else: internalError(n.info, "getField(record case branch)")
+      else: discard
   of nkSym:
     if n.sym.position == position: result = n.sym
   else: discard
 
-proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet)
+proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet; conf: ConfigRef)
 
-proc storeObj(s: var string; typ: PType; x: PNode; stored: var IntSet) =
-  internalAssert x.kind == nkObjConstr
+proc storeObj(s: var string; typ: PType; x: PNode; stored: var IntSet; conf: ConfigRef) =
+  assert x.kind == nkObjConstr
   let start = 1
   for i in countup(start, sonsLen(x) - 1):
     if i > start: s.add(", ")
     var it = x.sons[i]
     if it.kind == nkExprColonExpr:
-      internalAssert it.sons[0].kind == nkSym
-      let field = it.sons[0].sym
-      s.add(escapeJson(field.name.s))
-      s.add(": ")
-      storeAny(s, field.typ, it.sons[1], stored)
+      if it.sons[0].kind == nkSym:
+        let field = it.sons[0].sym
+        s.add(escapeJson(field.name.s))
+        s.add(": ")
+        storeAny(s, field.typ, it.sons[1], stored, conf)
     elif typ.n != nil:
       let field = getField(typ.n, i)
       s.add(escapeJson(field.name.s))
       s.add(": ")
-      storeAny(s, field.typ, it, stored)
+      storeAny(s, field.typ, it, stored, conf)
 
 proc skipColon*(n: PNode): PNode =
   result = n
   if n.kind == nkExprColonExpr:
     result = n.sons[1]
 
-proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
+proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet;
+              conf: ConfigRef) =
   case t.kind
   of tyNone: assert false
   of tyBool: s.add($(a.intVal != 0))
@@ -74,7 +76,7 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
       s.add("[")
       for i in 0 .. a.len-1:
         if i > 0: s.add(", ")
-        storeAny(s, t.elemType, a[i], stored)
+        storeAny(s, t.elemType, a[i], stored, conf)
       s.add("]")
   of tyTuple:
     s.add("{")
@@ -82,11 +84,11 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
       if i > 0: s.add(", ")
       s.add("\"Field" & $i)
       s.add("\": ")
-      storeAny(s, t.sons[i], a[i].skipColon, stored)
+      storeAny(s, t.sons[i], a[i].skipColon, stored, conf)
     s.add("}")
   of tyObject:
     s.add("{")
-    storeObj(s, t, a, stored)
+    storeObj(s, t, a, stored, conf)
     s.add("}")
   of tySet:
     s.add("[")
@@ -94,15 +96,16 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
       if i > 0: s.add(", ")
       if a[i].kind == nkRange:
         var x = copyNode(a[i][0])
-        storeAny(s, t.lastSon, x, stored)
+        storeAny(s, t.lastSon, x, stored, conf)
         while x.intVal+1 <= a[i][1].intVal:
           s.add(", ")
-          storeAny(s, t.lastSon, x, stored)
+          storeAny(s, t.lastSon, x, stored, conf)
           inc x.intVal
       else:
-        storeAny(s, t.lastSon, a[i], stored)
+        storeAny(s, t.lastSon, a[i], stored, conf)
     s.add("]")
-  of tyRange, tyGenericInst, tyAlias, tySink: storeAny(s, t.lastSon, a, stored)
+  of tyRange, tyGenericInst, tyAlias, tySink:
+    storeAny(s, t.lastSon, a, stored, conf)
   of tyEnum:
     # we need a slow linear search because of enums with holes:
     for e in items(t.n):
@@ -121,7 +124,7 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
       s.add("[")
       s.add($x.ptrToInt)
       s.add(", ")
-      storeAny(s, t.lastSon, a, stored)
+      storeAny(s, t.lastSon, a, stored, conf)
       s.add("]")
   of tyString, tyCString:
     if a.kind == nkNilLit or a.strVal.isNil: s.add("null")
@@ -129,14 +132,15 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
   of tyInt..tyInt64, tyUInt..tyUInt64: s.add($a.intVal)
   of tyFloat..tyFloat128: s.add($a.floatVal)
   else:
-    internalError a.info, "cannot marshal at compile-time " & t.typeToString
+    internalError conf, a.info, "cannot marshal at compile-time " & t.typeToString
 
-proc storeAny*(s: var string; t: PType; a: PNode) =
+proc storeAny*(s: var string; t: PType; a: PNode; conf: ConfigRef) =
   var stored = initIntSet()
-  storeAny(s, t, a, stored)
+  storeAny(s, t, a, stored, conf)
 
 proc loadAny(p: var JsonParser, t: PType,
-             tab: var Table[BiggestInt, PNode]): PNode =
+             tab: var Table[BiggestInt, PNode];
+             conf: ConfigRef): PNode =
   case t.kind
   of tyNone: assert false
   of tyBool:
@@ -170,7 +174,7 @@ proc loadAny(p: var JsonParser, t: PType,
     next(p)
     result = newNode(nkBracket)
     while p.kind != jsonArrayEnd and p.kind != jsonEof:
-      result.add loadAny(p, t.elemType, tab)
+      result.add loadAny(p, t.elemType, tab, conf)
     if p.kind == jsonArrayEnd: next(p)
     else: raiseParseErr(p, "']' end of array expected")
   of tySequence:
@@ -182,7 +186,7 @@ proc loadAny(p: var JsonParser, t: PType,
       next(p)
       result = newNode(nkBracket)
       while p.kind != jsonArrayEnd and p.kind != jsonEof:
-        result.add loadAny(p, t.elemType, tab)
+        result.add loadAny(p, t.elemType, tab, conf)
       if p.kind == jsonArrayEnd: next(p)
       else: raiseParseErr(p, "")
     else:
@@ -198,7 +202,7 @@ proc loadAny(p: var JsonParser, t: PType,
       next(p)
       if i >= t.len:
         raiseParseErr(p, "too many fields to tuple type " & typeToString(t))
-      result.add loadAny(p, t.sons[i], tab)
+      result.add loadAny(p, t.sons[i], tab, conf)
       inc i
     if p.kind == jsonObjectEnd: next(p)
     else: raiseParseErr(p, "'}' end of object expected")
@@ -220,7 +224,7 @@ proc loadAny(p: var JsonParser, t: PType,
         setLen(result.sons, pos + 1)
       let fieldNode = newNode(nkExprColonExpr)
       fieldNode.addSon(newSymNode(newSym(skField, ident, nil, unknownLineInfo())))
-      fieldNode.addSon(loadAny(p, field.typ, tab))
+      fieldNode.addSon(loadAny(p, field.typ, tab, conf))
       result.sons[pos] = fieldNode
     if p.kind == jsonObjectEnd: next(p)
     else: raiseParseErr(p, "'}' end of object expected")
@@ -229,7 +233,7 @@ proc loadAny(p: var JsonParser, t: PType,
     next(p)
     result = newNode(nkCurly)
     while p.kind != jsonArrayEnd and p.kind != jsonEof:
-      result.add loadAny(p, t.lastSon, tab)
+      result.add loadAny(p, t.lastSon, tab, conf)
       next(p)
     if p.kind == jsonArrayEnd: next(p)
     else: raiseParseErr(p, "']' end of array expected")
@@ -248,7 +252,7 @@ proc loadAny(p: var JsonParser, t: PType,
       if p.kind == jsonInt:
         let idx = p.getInt
         next(p)
-        result = loadAny(p, t.lastSon, tab)
+        result = loadAny(p, t.lastSon, tab, conf)
         tab[idx] = result
       else: raiseParseErr(p, "index for ref type expected")
       if p.kind == jsonArrayEnd: next(p)
@@ -275,14 +279,15 @@ proc loadAny(p: var JsonParser, t: PType,
       next(p)
       return
     raiseParseErr(p, "float expected")
-  of tyRange, tyGenericInst, tyAlias, tySink: result = loadAny(p, t.lastSon, tab)
+  of tyRange, tyGenericInst, tyAlias, tySink:
+    result = loadAny(p, t.lastSon, tab, conf)
   else:
-    internalError "cannot marshal at compile-time " & t.typeToString
+    internalError conf, "cannot marshal at compile-time " & t.typeToString
 
-proc loadAny*(s: string; t: PType): PNode =
+proc loadAny*(s: string; t: PType; conf: ConfigRef): PNode =
   var tab = initTable[BiggestInt, PNode]()
   var p: JsonParser
   open(p, newStringStream(s), "unknown file")
   next(p)
-  result = loadAny(p, t, tab)
+  result = loadAny(p, t, tab, conf)
   close(p)
diff --git a/compiler/vmops.nim b/compiler/vmops.nim
index 7f8bf06c1..617295b0d 100644
--- a/compiler/vmops.nim
+++ b/compiler/vmops.nim
@@ -15,8 +15,6 @@ from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
 
 from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir
 
-from options import gProjectPath
-
 template mathop(op) {.dirty.} =
   registerCallback(c, "stdlib.math." & astToStr(op), `op Wrapper`)
 
@@ -77,15 +75,15 @@ proc staticWalkDirImpl(path: string, relative: bool): PNode =
     result.add newTree(nkTupleConstr, newIntNode(nkIntLit, k.ord),
                               newStrNode(nkStrLit, f))
 
-proc gorgeExWrapper(a: VmArgs) {.nimcall.} =
-  let (s, e) = opGorge(getString(a, 0), getString(a, 1), getString(a, 2),
-                       a.currentLineInfo)
-  setResult a, newTree(nkTupleConstr, newStrNode(nkStrLit, s), newIntNode(nkIntLit, e))
+proc registerAdditionalOps*(c: PCtx) =
+  proc gorgeExWrapper(a: VmArgs) =
+    let (s, e) = opGorge(getString(a, 0), getString(a, 1), getString(a, 2),
+                         a.currentLineInfo, c.config)
+    setResult a, newTree(nkTupleConstr, newStrNode(nkStrLit, s), newIntNode(nkIntLit, e))
 
-proc getProjectPathWrapper(a: VmArgs) {.nimcall.} =
-  setResult a, gProjectPath
+  proc getProjectPathWrapper(a: VmArgs) =
+    setResult a, c.config.projectPath
 
-proc registerAdditionalOps*(c: PCtx) =
   wrap1f_math(sqrt)
   wrap1f_math(ln)
   wrap1f_math(log10)
diff --git a/compiler/writetracking.nim b/compiler/writetracking.nim
index e03d6fb59..c0f7b7b20 100644
--- a/compiler/writetracking.nim
+++ b/compiler/writetracking.nim
@@ -15,7 +15,7 @@
 ##   * Computing an aliasing relation based on the assignments. This relation
 ##     is then used to compute the 'writes' and 'escapes' effects.
 
-import intsets, idents, ast, astalgo, trees, renderer, msgs, types
+import intsets, idents, ast, astalgo, trees, renderer, msgs, types, options
 
 const
   debug = false
@@ -180,7 +180,7 @@ proc deps(w: var W; n: PNode) =
       let last = lastSon(child)
       if last.kind == nkEmpty: continue
       if child.kind == nkVarTuple and last.kind in {nkPar, nkTupleConstr}:
-        internalAssert child.len-2 == last.len
+        if child.len-2 != last.len: return
         for i in 0 .. child.len-3:
           deps(w, child.sons[i], last.sons[i], {})
       else:
@@ -220,7 +220,7 @@ proc possibleAliases(w: var W; result: var seq[ptr TSym]) =
         # x = f(..., y, ....)
         for i in 0 ..< a.srcNoTc: addNoDup a.src[i]
 
-proc markWriteOrEscape(w: var W) =
+proc markWriteOrEscape(w: var W; conf: ConfigRef) =
   ## Both 'writes' and 'escapes' effects ultimately only care
   ## about *parameters*.
   ## However, due to aliasing, even locals that might not look as parameters
@@ -249,7 +249,7 @@ proc markWriteOrEscape(w: var W) =
         if p.kind == skParam and p.owner == w.owner:
           incl(p.flags, sfWrittenTo)
           if w.owner.kind == skFunc and p.typ.kind != tyVar:
-            localError(a.info, "write access to non-var parameter: " & p.name.s)
+            localError(conf, a.info, "write access to non-var parameter: " & p.name.s)
 
     if {rootIsResultOrParam, rootIsHeapAccess, markAsEscaping}*a.destInfo != {}:
       var destIsParam = false
@@ -263,14 +263,14 @@ proc markWriteOrEscape(w: var W) =
           if p.kind == skParam and p.owner == w.owner:
             incl(p.flags, sfEscapes)
 
-proc trackWrites*(owner: PSym; body: PNode) =
+proc trackWrites*(owner: PSym; body: PNode; conf: ConfigRef) =
   var w: W
   w.owner = owner
   w.assignments = @[]
   # Phase 1: Collect and preprocess any assignments in the proc body:
   deps(w, body)
   # Phase 2: Compute the 'writes' and 'escapes' effects:
-  markWriteOrEscape(w)
+  markWriteOrEscape(w, conf)
   if w.returnsNew != asgnOther and not isEmptyType(owner.typ.sons[0]) and
       containsGarbageCollectedRef(owner.typ.sons[0]):
     incl(owner.typ.flags, tfReturnsNew)