summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim16
-rw-r--r--compiler/ccgcalls.nim8
-rw-r--r--compiler/ccgexprs.nim76
-rw-r--r--compiler/ccgstmts.nim4
-rw-r--r--compiler/ccgtrav.nim4
-rw-r--r--compiler/ccgtypes.nim42
-rw-r--r--compiler/ccgutils.nim4
-rw-r--r--compiler/cgen.nim11
-rw-r--r--compiler/cgendata.nim5
-rw-r--r--compiler/cgmeth.nim14
-rw-r--r--compiler/commands.nim12
-rw-r--r--compiler/condsyms.nim9
-rw-r--r--compiler/docgen.nim140
-rw-r--r--compiler/docgen2.nim23
-rw-r--r--compiler/extccomp.nim2
-rw-r--r--compiler/idgen.nim8
-rw-r--r--compiler/installer.ini2
-rw-r--r--compiler/jsgen.nim85
-rw-r--r--compiler/jstypes.nim3
-rw-r--r--compiler/lexer.nim11
-rw-r--r--compiler/lookups.nim3
-rw-r--r--compiler/lowerings.nim1
-rw-r--r--compiler/main.nim15
-rw-r--r--compiler/modules.nim43
-rw-r--r--compiler/msgs.nim6
-rw-r--r--compiler/nimfix/pretty.nim8
-rw-r--r--compiler/options.nim70
-rw-r--r--compiler/packagehandling.nim56
-rw-r--r--compiler/parser.nim14
-rw-r--r--compiler/passaux.nim2
-rw-r--r--compiler/patterns.nim2
-rw-r--r--compiler/platform.nim5
-rw-r--r--compiler/pragmas.nim9
-rw-r--r--compiler/renderer.nim8
-rw-r--r--compiler/rodutils.nim2
-rw-r--r--compiler/scriptconfig.nim19
-rw-r--r--compiler/sem.nim39
-rw-r--r--compiler/semasgn.nim2
-rw-r--r--compiler/semcall.nim41
-rw-r--r--compiler/semdata.nim3
-rw-r--r--compiler/semdestruct.nim1
-rw-r--r--compiler/semexprs.nim40
-rw-r--r--compiler/semfold.nim23
-rw-r--r--compiler/semgnrc.nim7
-rw-r--r--compiler/seminst.nim2
-rw-r--r--compiler/semmagic.nim5
-rw-r--r--compiler/semparallel.nim6
-rw-r--r--compiler/semstmts.nim33
-rw-r--r--compiler/semtypes.nim28
-rw-r--r--compiler/semtypinst.nim21
-rw-r--r--compiler/sigmatch.nim77
-rw-r--r--compiler/types.nim19
-rw-r--r--compiler/vmdeps.nim133
-rw-r--r--compiler/vmgen.nim55
-rw-r--r--compiler/wordrecg.nim3
55 files changed, 886 insertions, 394 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 73c99c0b1..4c98219f9 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -395,6 +395,9 @@ type
       # sons[1]: field type
       # .n: nkDotExpr storing the field name
 
+    tyVoid #\
+      # now different from tyEmpty, hurray!
+
 static:
   # remind us when TTypeKind stops to fit in a single 64-bit word
   assert TTypeKind.high.ord <= 63
@@ -528,8 +531,6 @@ const
   tfOldSchoolExprStmt* = tfVarargs # for now used to distinguish \
     # 'varargs[expr]' from 'varargs[untyped]'. Eventually 'expr' will be
     # deprecated and this mess can be cleaned up.
-  tfVoid* = tfVarargs # for historical reasons we conflated 'void' with
-                      # 'empty' ('@[]' has the type 'seq[empty]').
   tfReturnsNew* = tfInheritable
   skError* = skUnknown
 
@@ -544,7 +545,7 @@ type
     mEcho, mShallowCopy, mSlurp, mStaticExec,
     mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
     mUnaryLt, mInc, mDec, mOrd,
-    mNew, mNewFinalize, mNewSeq,
+    mNew, mNewFinalize, mNewSeq, mNewSeqOfCap,
     mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq,
     mXLenStr, mXLenSeq,
     mIncl, mExcl, mCard, mChr,
@@ -590,6 +591,7 @@ type
     mNewString, mNewStringOfCap, mParseBiggestFloat,
     mReset,
     mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
+    mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
     mOrdinal,
     mInt, mInt8, mInt16, mInt32, mInt64,
     mUInt, mUInt8, mUInt16, mUInt32, mUInt64,
@@ -609,7 +611,7 @@ type
     mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl,
     mNHint, mNWarning, mNError,
     mInstantiationInfo, mGetTypeInfo, mNGenSym,
-    mNimvm
+    mNimvm, mIntDefine, mStrDefine
 
 # things that we can evaluate safely at compile time, even if not asked for it:
 const
@@ -769,7 +771,7 @@ type
       procInstCache*: seq[PInstantiation]
       gcUnsafetyReason*: PSym  # for better error messages wrt gcsafe
       #scope*: PScope          # the scope where the proc was defined
-    of skModule:
+    of skModule, skPackage:
       # modules keep track of the generic symbols they use from other modules.
       # this is because in incremental compilation, when a module is about to
       # be replaced with a newer version, we must decrement the usage count
@@ -848,6 +850,7 @@ type
                               # see instantiateDestructor in semdestruct.nim
     deepCopy*: PSym           # overriden 'deepCopy' operation
     assignment*: PSym         # overriden '=' operator
+    methods*: seq[(int,PSym)] # attached methods
     size*: BiggestInt         # the size of the type in bytes
                               # -1 means that the size is unkwown
     align*: int16             # the type's alignment requirements
@@ -963,7 +966,6 @@ const
 var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things
 var
   gMainPackageId*: int
-  gMainPackageNotes*: TNoteKinds
 
 proc isCallExpr*(n: PNode): bool =
   result = n.kind in nkCallKinds
@@ -1587,7 +1589,7 @@ proc isAtom*(n: PNode): bool {.inline.} =
 
 proc isEmptyType*(t: PType): bool {.inline.} =
   ## 'void' and 'stmt' types are often equivalent to 'nil' these days:
-  result = t == nil or t.kind in {tyEmpty, tyStmt}
+  result = t == nil or t.kind in {tyVoid, tyStmt}
 
 proc makeStmtList*(n: PNode): PNode =
   if n.kind == nkStmtList:
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index bd17f85e4..dffb8a9a5 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -124,7 +124,7 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
         result = "(*$1)->data, (*$1)->$2" % [a.rdLoc, lenField(p)]
       of tyArray, tyArrayConstr:
         result = "$1, $2" % [rdLoc(a), rope(lengthOrd(lastSon(a.t)))]
-      else: 
+      else:
         internalError("openArrayLoc: " & typeToString(a.t))
     else: internalError("openArrayLoc: " & typeToString(a.t))
 
@@ -260,7 +260,11 @@ proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
     else:
       result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym)
   else:
-    result = genArgNoParam(p, ri.sons[i])
+    if tfVarargs notin typ.flags:
+      localError(ri.info, "wrong argument count")
+      result = nil
+    else:
+      result = genArgNoParam(p, ri.sons[i])
 
 discard """
 Dot call syntax in C++
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 8fe9cdb72..3f12fed2c 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -45,7 +45,7 @@ proc genHexLiteral(v: PNode): Rope =
 
 proc getStrLit(m: BModule, s: string): Rope =
   discard cgsym(m, "TGenericSeq")
-  result = "TMP" & rope(backendId())
+  result = getTempName(m)
   addf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n",
        [result, makeCString(s), rope(len(s))])
 
@@ -67,11 +67,11 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
   of nkNilLit:
     let t = skipTypes(ty, abstractVarRange)
     if t.kind == tyProc and t.callConv == ccClosure:
-      var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
-      result = "TMP" & rope(id)
-      if id == gBackendId:
+      let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
+      result = p.module.tmpBase & rope(id)
+      if id == p.module.labels:
         # not found in cache:
-        inc(gBackendId)
+        inc(p.module.labels)
         addf(p.module.s[cfsData],
              "static NIM_CONST $1 $2 = {NIM_NIL,NIM_NIL};$n",
              [getTypeDesc(p.module, t), result])
@@ -81,13 +81,14 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
     if n.strVal.isNil:
       result = ropecg(p.module, "((#NimStringDesc*) NIM_NIL)", [])
     elif skipTypes(ty, abstractVarRange).kind == tyString:
-      var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
-      if id == gBackendId:
+      let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
+      if id == p.module.labels:
         # string literal not found in the cache:
         result = ropecg(p.module, "((#NimStringDesc*) &$1)",
                         [getStrLit(p.module, n.strVal)])
       else:
-        result = ropecg(p.module, "((#NimStringDesc*) &TMP$1)", [rope(id)])
+        result = ropecg(p.module, "((#NimStringDesc*) &$1$2)",
+                        [p.module.tmpBase, rope(id)])
     else:
       result = makeCString(n.strVal)
   of nkFloatLit..nkFloat64Lit:
@@ -134,11 +135,11 @@ proc genSetNode(p: BProc, n: PNode): Rope =
   var size = int(getSize(n.typ))
   toBitSet(n, cs)
   if size > 8:
-    var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
-    result = "TMP" & rope(id)
-    if id == gBackendId:
+    let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
+    result = p.module.tmpBase & rope(id)
+    if id == p.module.labels:
       # not found in cache:
-      inc(gBackendId)
+      inc(p.module.labels)
       addf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n",
            [getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)])
   else:
@@ -490,7 +491,7 @@ proc binaryArithOverflowRaw(p: BProc, t: PType, a, b: TLoc;
   var size = getSize(t)
   let storage = if size < platform.intSize: rope("NI")
                 else: getTypeDesc(p.module, t)
-  result = getTempName()
+  result = getTempName(p.module)
   linefmt(p, cpsLocals, "$1 $2;$n", storage, result)
   lineCg(p, cpsStmts, frmt, result, rdCharLoc(a), rdCharLoc(b))
   if size < platform.intSize or t.kind in {tyRange, tyEnum}:
@@ -801,9 +802,9 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym;
     v.r.add(d.loc.r)
     genInExprAux(p, it, u, v, test)
     let id = nodeTableTestOrSet(p.module.dataCache,
-                               newStrNode(nkStrLit, field.name.s), gBackendId)
-    let strLit = if id == gBackendId: getStrLit(p.module, field.name.s)
-                 else: "TMP" & rope(id)
+                               newStrNode(nkStrLit, field.name.s), p.module.labels)
+    let strLit = if id == p.module.labels: getStrLit(p.module, field.name.s)
+                 else: p.module.tmpBase & rope(id)
     if op.magic == mNot:
       linefmt(p, cpsStmts,
               "if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
@@ -1140,6 +1141,16 @@ proc genNewSeq(p: BProc, e: PNode) =
   genNewSeqAux(p, a, b.rdLoc)
   gcUsage(e)
 
+proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
+  let seqtype = skipTypes(e.typ, abstractVarRange)
+  var a: TLoc
+  initLocExpr(p, e.sons[1], a)
+  putIntoDest(p, d, e.typ, ropecg(p.module,
+              "($1)#nimNewSeqOfCap($2, $3)", [
+              getTypeDesc(p.module, seqtype),
+              genTypeInfo(p.module, seqtype), a.rdLoc]))
+  gcUsage(e)
+
 proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
   var tmp: TLoc
   var t = e.typ.skipTypes(abstractInst)
@@ -1319,7 +1330,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
     putIntoDest(p, d, e.typ,
                 ropecg(p.module, "#reprAny($1, $2)", [
                 rdLoc(a), genTypeInfo(p.module, t)]), a.s)
-  of tyEmpty:
+  of tyEmpty, tyVoid:
     localError(e.info, "'repr' doesn't support 'void' type")
   else:
     putIntoDest(p, d, e.typ, ropecg(p.module, "#reprAny($1, $2)",
@@ -1557,11 +1568,12 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
         [getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.s)
 
 proc genCast(p: BProc, e: PNode, d: var TLoc) =
-  const floatTypes = {tyFloat..tyFloat128}
+  const ValueTypes = {tyFloat..tyFloat128, tyTuple, tyObject,
+                      tyArray, tyArrayConstr}
   let
     destt = skipTypes(e.typ, abstractRange)
     srct = skipTypes(e.sons[1].typ, abstractRange)
-  if destt.kind in floatTypes or srct.kind in floatTypes:
+  if destt.kind in ValueTypes or srct.kind in ValueTypes:
     # 'cast' and some float type involved? --> use a union.
     inc(p.labels)
     var lbl = p.labels.rope
@@ -1667,10 +1679,10 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     if optOverflowCheck notin p.options: unaryExpr(p, e, d, "($1 - 1)")
     else: unaryExpr(p, e, d, "#subInt($1, 1)")
   of mInc, mDec:
-    const opr: array [mInc..mDec, string] = ["$1 += $2;$n", "$1 -= $2;$n"]
-    const fun64: array [mInc..mDec, string] = ["$# = #addInt64($#, $#);$n",
+    const opr: array[mInc..mDec, string] = ["$1 += $2;$n", "$1 -= $2;$n"]
+    const fun64: array[mInc..mDec, string] = ["$# = #addInt64($#, $#);$n",
                                                "$# = #subInt64($#, $#);$n"]
-    const fun: array [mInc..mDec, string] = ["$# = #addInt($#, $#);$n",
+    const fun: array[mInc..mDec, string] = ["$# = #addInt($#, $#);$n",
                                              "$# = #subInt($#, $#);$n"]
     let underlying = skipTypes(e.sons[1].typ, {tyGenericInst, tyVar, tyRange})
     if optOverflowCheck notin p.options or underlying.kind in {tyUInt..tyUInt64}:
@@ -1711,6 +1723,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   of mNew: genNew(p, e)
   of mNewFinalize: genNewFinalize(p, e)
   of mNewSeq: genNewSeq(p, e)
+  of mNewSeqOfCap: genNewSeqOfCap(p, e, d)
   of mSizeOf:
     let t = e.sons[1].typ.skipTypes({tyTypeDesc})
     putIntoDest(p, d, e.typ, "((NI)sizeof($1))" % [getTypeDesc(p.module, t)])
@@ -1761,11 +1774,11 @@ proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
   if nfAllConst in n.flags and d.k == locNone and n.len > 0 and n.isDeepConstExpr:
     var t = getUniqueType(n.typ)
     discard getTypeDesc(p.module, t) # so that any fields are initialized
-    var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
-    fillLoc(d, locData, t, "TMP" & rope(id), OnStatic)
-    if id == gBackendId:
+    let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
+    fillLoc(d, locData, t, p.module.tmpBase & rope(id), OnStatic)
+    if id == p.module.labels:
       # expression not found in the cache:
-      inc(gBackendId)
+      inc(p.module.labels)
       addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
            [getTypeDesc(p.module, t), d.r, genConstExpr(p, n)])
     result = true
@@ -1952,12 +1965,12 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
 proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
   var t = getUniqueType(n.typ)
   discard getTypeDesc(p.module, t) # so that any fields are initialized
-  var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
-  var tmp = "TMP" & rope(id)
+  let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
+  let tmp = p.module.tmpBase & rope(id)
 
-  if id == gBackendId:
+  if id == p.module.labels:
     # expression not found in the cache:
-    inc(gBackendId)
+    inc(p.module.labels)
     addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
          [getTypeDesc(p.module, t), tmp, genConstExpr(p, n)])
 
@@ -2179,8 +2192,7 @@ proc genConstSeq(p: BProc, n: PNode, t: PType): Rope =
     data.add("}")
   data.add("}")
 
-  inc(gBackendId)
-  result = "CNSTSEQ" & gBackendId.rope
+  result = getTempName(p.module)
 
   appcg(p.module, cfsData,
         "NIM_CONST struct {$n" &
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 64933df78..70d50b060 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -793,7 +793,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
   if not isEmptyType(t.typ) and d.k == locNone:
     getTemp(p, t.typ, d)
   genLineDir(p, t)
-  let exc = getTempName()
+  let exc = getTempName(p.module)
   if getCompilerProc("Exception") != nil:
     discard cgsym(p.module, "Exception")
   else:
@@ -886,7 +886,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
     getTemp(p, t.typ, d)
   discard lists.includeStr(p.module.headerFiles, "<setjmp.h>")
   genLineDir(p, t)
-  var safePoint = getTempName()
+  var safePoint = getTempName(p.module)
   if getCompilerProc("Exception") != nil:
     discard cgsym(p.module, "Exception")
   else:
diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim
index 0da6396ea..dfefc4b63 100644
--- a/compiler/ccgtrav.nim
+++ b/compiler/ccgtrav.nim
@@ -100,7 +100,7 @@ proc genTraverseProcSeq(c: var TTraversalClosure, accessor: Rope, typ: PType) =
 proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): Rope =
   var c: TTraversalClosure
   var p = newProc(nil, m)
-  result = getGlobalTempName()
+  result = getTempName(m)
 
   case reason
   of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n"
@@ -135,7 +135,7 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope =
   var c: TTraversalClosure
   var p = newProc(nil, m)
   var sLoc = s.loc.r
-  result = getGlobalTempName()
+  result = getTempName(m)
 
   if sfThread in s.flags and emulatedThreadVars():
     accessThreadLocalVar(p, s)
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 4de196fe0..3d1c2affc 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -25,8 +25,9 @@ proc isKeyword(w: PIdent): bool =
 proc mangleField(name: PIdent): string =
   result = mangle(name.s)
   if isKeyword(name):
-    result[0] = result[0].toUpper # Mangling makes everything lowercase,
-                                  # but some identifiers are C keywords
+    result[0] = result[0].toUpperAscii
+    # Mangling makes everything lowercase,
+    # but some identifiers are C keywords
 
 proc hashOwner(s: PSym): FilenameHash =
   var m = s
@@ -150,6 +151,9 @@ proc mapType(typ: PType): TCTypeKind =
   of tyCString: result = ctCString
   of tyInt..tyUInt64:
     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")
 
 proc mapReturnType(typ: PType): TCTypeKind =
@@ -202,11 +206,9 @@ proc cacheGetType(tab: TIdTable, key: PType): Rope =
   # linear search is not necessary anymore:
   result = Rope(idTableGet(tab, key))
 
-proc getTempName(): Rope =
-  result = rfmt(nil, "TMP$1", rope(backendId()))
-
-proc getGlobalTempName(): Rope =
-  result = rfmt(nil, "TMP$1", rope(backendId()))
+proc getTempName(m: BModule): Rope =
+  result = m.tmpBase & rope(m.labels)
+  inc m.labels
 
 proc ccgIntroducedPtr(s: PSym): bool =
   var pt = skipTypes(s.typ, typedescInst)
@@ -258,6 +260,11 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
   of tyInt..tyUInt64:
     result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind])
   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")
+  of tyGenericInst:
+    result = getSimpleTypeDesc(m, lastSon typ)
   else: result = nil
 
 proc pushType(m: BModule, typ: PType) =
@@ -418,7 +425,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
       addf(result, "union{$n$1} $2;$n", [unionBody, uname])
   of nkSym:
     field = n.sym
-    if field.typ.kind == tyEmpty: return
+    if field.typ.kind == tyVoid: return
     #assert(field.ast == nil)
     sname = mangleRecFieldName(field, rectype)
     if accessExpr != nil: ae = "$1.$2" % [accessExpr, sname]
@@ -665,7 +672,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
             chunkStart = i
 
             let typeInSlot = resolveStarsInCppType(typ, idx + 1, stars)
-            if typeInSlot == nil or typeInSlot.kind == tyEmpty:
+            if typeInSlot == nil or typeInSlot.kind == tyVoid:
               result.add(~"void")
             else:
               result.add getTypeDescAux(m, typeInSlot, check)
@@ -724,7 +731,7 @@ type
 proc getClosureType(m: BModule, t: PType, kind: TClosureTypeKind): Rope =
   assert t.kind == tyProc
   var check = initIntSet()
-  result = getTempName()
+  result = getTempName(m)
   var rettype, desc: Rope
   genProcParams(m, t, rettype, desc, check, declareEnvironment=kind != clHalf)
   if not isImportedType(t):
@@ -839,7 +846,7 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: Rope) =
     if L == 1:
       genObjectFields(m, typ, n.sons[0], expr)
     elif L > 0:
-      var tmp = getTempName()
+      var tmp = getTempName(m)
       addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(L)])
       for i in countup(0, L-1):
         var tmp2 = getNimNode(m)
@@ -911,7 +918,7 @@ proc genTupleInfo(m: BModule, typ: PType, name: Rope) =
   var expr = getNimNode(m)
   var length = sonsLen(typ)
   if length > 0:
-    var tmp = getTempName()
+    var tmp = getTempName(m)
     addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(length)])
     for i in countup(0, length - 1):
       var a = typ.sons[i]
@@ -935,7 +942,7 @@ proc genEnumInfo(m: BModule, typ: PType, name: Rope) =
   # anyway. We generate a cstring array and a loop over it. Exceptional
   # positions will be reset after the loop.
   genTypeInfoAux(m, typ, typ, name)
-  var nodePtrs = getTempName()
+  var nodePtrs = getTempName(m)
   var length = sonsLen(typ.n)
   addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n",
        [nodePtrs, rope(length)])
@@ -955,8 +962,8 @@ proc genEnumInfo(m: BModule, typ: PType, name: Rope) =
     if field.position != i or tfEnumHasHoles in typ.flags:
       addf(specialCases, "$1.offset = $2;$n", [elemNode, rope(field.position)])
       hasHoles = true
-  var enumArray = getTempName()
-  var counter = getTempName()
+  var enumArray = getTempName(m)
+  var counter = getTempName(m)
   addf(m.s[cfsTypeInit1], "NI $1;$n", [counter])
   addf(m.s[cfsTypeInit1], "static char* NIM_CONST $1[$2] = {$n$3};$n",
        [enumArray, rope(length), enumNames])
@@ -1024,9 +1031,12 @@ proc genTypeInfo(m: BModule, t: PType): Rope =
          [result, rope(typeToString(t))])
     return "(&".rope & result & ")".rope
   case t.kind
-  of tyEmpty: result = rope"0"
+  of tyEmpty, tyVoid: result = rope"0"
   of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
     genTypeInfoAuxBase(m, t, t, result, rope"0")
+  of tyStatic:
+    if t.n != nil: result = genTypeInfo(m, lastSon t)
+    else: internalError("genTypeInfo(" & $t.kind & ')')
   of tyProc:
     if t.callConv != ccClosure:
       genTypeInfoAuxBase(m, t, t, result, rope"0")
diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim
index 6dfd7b52c..ecd98a2bf 100644
--- a/compiler/ccgutils.nim
+++ b/compiler/ccgutils.nim
@@ -93,7 +93,7 @@ proc getUniqueType*(key: PType): PType =
     # produced instead of ``NI``.
     result = key
   of  tyEmpty, tyNil, tyExpr, tyStmt, tyPointer, tyString,
-      tyCString, tyNone, tyBigNum:
+      tyCString, tyNone, tyBigNum, tyVoid:
     result = gCanonicalTypes[k]
     if result == nil:
       gCanonicalTypes[k] = key
@@ -188,7 +188,7 @@ proc mangle*(name: string): string =
     let c = name[i]
     case c
     of 'A'..'Z':
-      add(result, c.toLower)
+      add(result, c.toLowerAscii)
     of '_':
       discard
     of 'a'..'z', '0'..'9':
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 3334f047f..589fcb515 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -500,7 +500,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
   assert(lib != nil)
   if not lib.generated:
     lib.generated = true
-    var tmp = getGlobalTempName()
+    var tmp = getTempName(m)
     assert(lib.name == nil)
     lib.name = tmp # BUGFIX: cgsym has awful side-effects
     addf(m.s[cfsVars], "static void* $1;$n", [tmp])
@@ -1084,6 +1084,7 @@ proc initProcOptions(m: BModule): TOptions =
 
 proc rawNewModule(module: PSym, filename: string): BModule =
   new(result)
+  result.tmpBase = rope("T" & $hashOwner(module) & "_")
   initLinkedList(result.headerFiles)
   result.declaredThings = initIntSet()
   result.declaredProtos = initIntSet()
@@ -1100,8 +1101,8 @@ proc rawNewModule(module: PSym, filename: string): BModule =
   initNodeTable(result.dataCache)
   result.typeStack = @[]
   result.forwardedProcs = @[]
-  result.typeNodesName = getTempName()
-  result.nimTypesName = getTempName()
+  result.typeNodesName = getTempName(result)
+  result.nimTypesName = getTempName(result)
   # 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:
@@ -1126,8 +1127,8 @@ proc resetModule*(m: BModule) =
   initNodeTable(m.dataCache)
   m.typeStack = @[]
   m.forwardedProcs = @[]
-  m.typeNodesName = getTempName()
-  m.nimTypesName = getTempName()
+  m.typeNodesName = getTempName(m)
+  m.nimTypesName = getTempName(m)
   if sfSystemModule in m.module.flags:
     incl m.flags, preventStackTrace
   else:
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index c098902a6..c027bb451 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -102,12 +102,13 @@ type
     includesStringh,    # C source file already includes ``<string.h>``
     objHasKidsValid     # whether we can rely on tfObjHasKids
   TCGen = object of TPassContext # represents a C source file
-    module*: PSym
-    filename*: string
     s*: TCFileSections        # sections of the C file
     flags*: set[Codegenflag]
+    module*: PSym
+    filename*: string
     cfilename*: string        # filename of the module (including path,
                               # without extension)
+    tmpBase*: Rope            # base for temp identifier generation
     typeCache*: TIdTable      # cache the generated types
     forwTypeCache*: TIdTable  # cache for forward declarations of types
     declaredThings*: IntSet  # things we have declared in this .c file
diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim
index 312afec1a..624c5b183 100644
--- a/compiler/cgmeth.nim
+++ b/compiler/cgmeth.nim
@@ -63,19 +63,25 @@ proc sameMethodBucket(a, b: PSym): MethodResult =
     while true:
       aa = skipTypes(aa, {tyGenericInst})
       bb = skipTypes(bb, {tyGenericInst})
-      if (aa.kind == bb.kind) and (aa.kind in {tyVar, tyPtr, tyRef}):
+      if aa.kind == bb.kind and aa.kind in {tyVar, tyPtr, tyRef}:
         aa = aa.lastSon
         bb = bb.lastSon
       else:
         break
     if sameType(aa, bb):
-      if aa.kind == tyObject and result != Invalid: result = Yes
+      if aa.kind == tyObject and result != Invalid:
+        result = Yes
     elif aa.kind == tyObject and bb.kind == tyObject:
       let diff = inheritanceDiff(bb, aa)
       if diff < 0:
-        if result != Invalid: result = Yes
+        if result != Invalid:
+          result = Yes
+        else:
+          return No
       elif diff != high(int):
         result = Invalid
+      else:
+        return No
     else:
       return No
 
@@ -181,7 +187,7 @@ proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
       var aa = skipTypes(a.typ.sons[col], skipPtrs)
       var bb = skipTypes(b.typ.sons[col], skipPtrs)
       var d = inheritanceDiff(aa, bb)
-      if (d != high(int)):
+      if (d != high(int)) and d != 0:
         return d
 
 proc sortBucket(a: var TSymSeq, relevantCols: IntSet) =
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 5601ef662..b468dd6b8 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -158,7 +158,7 @@ var
   enableNotes: TNoteKinds
   disableNotes: TNoteKinds
 
-proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
+proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
                          info: TLineInfo; orig: string) =
   var id = ""  # arg = "X]:on|off"
   var i = 0
@@ -181,10 +181,13 @@ proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
   case whichKeyword(substr(arg, i))
   of wOn:
     incl(gNotes, n)
+    incl(gMainPackageNotes, n)
     incl(enableNotes, n)
   of wOff:
     excl(gNotes, n)
+    excl(gMainPackageNotes, n)
     incl(disableNotes, n)
+    excl(ForeignPackageNotes, n)
   else: localError(info, errOnOrOffExpectedButXFound, arg)
 
 proc processCompile(filename: string) =
@@ -341,7 +344,11 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
     discard "allow for backwards compatibility, but don't do anything"
   of "define", "d":
     expectArg(switch, arg, pass, info)
-    defineSymbol(arg)
+    if {':', '='} in arg:
+      splitSwitch(arg, key, val, pass, info)
+      defineSymbol(key, val)
+    else:
+      defineSymbol(arg)
   of "undef", "u":
     expectArg(switch, arg, pass, info)
     undefSymbol(arg)
@@ -543,6 +550,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
     gNotes = NotesVerbosity[gVerbosity]
     incl(gNotes, enableNotes)
     excl(gNotes, disableNotes)
+    gMainPackageNotes = gNotes
   of "parallelbuild":
     expectArg(switch, arg, pass, info)
     gNumberOfProcessors = parseInt(arg)
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index 60e8f2826..02f7e764d 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -19,8 +19,8 @@ var gSymbols: StringTableRef
 const
   catNone = "false"
 
-proc defineSymbol*(symbol: string) =
-  gSymbols[symbol] = "true"
+proc defineSymbol*(symbol: string, value: string = "true") =
+  gSymbols[symbol] = value
 
 proc undefSymbol*(symbol: string) =
   gSymbols[symbol] = catNone
@@ -62,6 +62,11 @@ proc isDefined*(symbol: string): bool =
 
 proc isDefined*(symbol: PIdent): bool = isDefined(symbol.s)
 
+proc lookupSymbol*(symbol: string): string =
+  result = if isDefined(symbol): gSymbols[symbol] else: nil
+
+proc lookupSymbol*(symbol: PIdent): string = lookupSymbol(symbol.s)
+
 iterator definedSymbolNames*: string =
   for key, val in pairs(gSymbols):
     if val != catNone: yield key
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index d954b897b..bbbec081a 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -14,7 +14,7 @@
 import
   ast, strutils, strtabs, options, msgs, os, ropes, idents,
   wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite,
-  importer, sempass2, json, xmltree, cgi, typesrenderer
+  importer, sempass2, json, xmltree, cgi, typesrenderer, astalgo
 
 type
   TSections = array[TSymKind, Rope]
@@ -25,9 +25,32 @@ type
     indexValFilename: string
     analytics: string  # Google Analytics javascript, "" if doesn't exist
     seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML.
+    jArray: JsonNode
+    types: TStrTable
 
   PDoc* = ref TDocumentor ## Alias to type less.
 
+proc whichType(d: PDoc; n: PNode): PSym =
+  if n.kind == nkSym:
+    if d.types.strTableContains(n.sym):
+      result = n.sym
+  else:
+    for i in 0..<safeLen(n):
+      let x = whichType(d, n[i])
+      if x != nil: return x
+
+proc attachToType(d: PDoc; p: PSym): PSym =
+  let params = p.ast.sons[paramsPos]
+  # first check the first parameter, then the return type,
+  # then the other parameter:
+  template check(i) =
+    result = whichType(d, params[i])
+    if result != nil: return result
+
+  if params.len > 1: check(1)
+  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:
@@ -81,6 +104,8 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
 
   result.seenSymbols = newStringTable(modeCaseInsensitive)
   result.id = 100
+  result.jArray = newJArray()
+  initStrTable result.types
 
 proc dispA(dest: var Rope, xml, tex: string, args: openArray[Rope]) =
   if gCmd != cmdRst2tex: addf(dest, xml, args)
@@ -226,10 +251,27 @@ proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
     result = esc(d.target, "`")
     for i in 0.. <n.len: result.add(getName(d, n[i], splitAfter))
     result.add esc(d.target, "`")
+  of nkOpenSymChoice, nkClosedSymChoice:
+    result = getName(d, n[0], splitAfter)
   else:
     internalError(n.info, "getName()")
     result = ""
 
+proc getNameIdent(n: PNode): PIdent =
+  case n.kind
+  of nkPostfix: result = getNameIdent(n.sons[1])
+  of nkPragmaExpr: result = getNameIdent(n.sons[0])
+  of nkSym: result = n.sym.name
+  of nkIdent: result = n.ident
+  of nkAccQuoted:
+    var r = ""
+    for i in 0.. <n.len: r.add(getNameIdent(n[i]).s)
+    result = getIdent(r)
+  of nkOpenSymChoice, nkClosedSymChoice:
+    result = getNameIdent(n[0])
+  else:
+    result = nil
+
 proc getRstName(n: PNode): PRstNode =
   case n.kind
   of nkPostfix: result = getRstName(n.sons[1])
@@ -239,6 +281,8 @@ proc getRstName(n: PNode): PRstNode =
   of nkAccQuoted:
     result = getRstName(n.sons[0])
     for i in 1 .. <n.len: result.text.add(getRstName(n[i]).text)
+  of nkOpenSymChoice, nkClosedSymChoice:
+    result = getRstName(n[0])
   else:
     internalError(n.info, "getRstName()")
     result = nil
@@ -311,7 +355,7 @@ proc docstringSummary(rstText: string): string =
   ## Also, we hope to not break the rst, but maybe we do. If there is any
   ## trimming done, an ellipsis unicode char is added.
   const maxDocstringChars = 100
-  assert (rstText.len < 2 or (rstText[0] == '#' and rstText[1] == '#'))
+  assert(rstText.len < 2 or (rstText[0] == '#' and rstText[1] == '#'))
   result = rstText.substr(2).strip
   var pos = result.find('\L')
   if pos > 0:
@@ -380,13 +424,27 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
             "\\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">""",
+                    "\\spanOther{$1}",
+                  [rope(esc(d.target, literal))])
+    of tkCurlyDotRi:
+      dispA(result, "</div><span class=\"Other pragmaend\">$1</span>",
+                    "\\spanOther{$1}",
+                  [rope(esc(d.target, literal))])
     of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
-       tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe,
+       tkBracketDotLe, tkBracketDotRi, tkParDotLe,
        tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
        tkAccent, tkColonColon,
        tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr:
       dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
             [rope(esc(d.target, literal))])
+
+  if k in routineKinds and nameNode.kind == nkSym:
+    let att = attachToType(d, nameNode.sym)
+    if att != nil:
+      dispA(result, """<span class="attachedType" style="visibility:hidden">$1</span>""", "",
+        [rope esc(d.target, att.name.s)])
   inc(d.id)
   let
     plainNameRope = rope(xmltree.escape(plainName.strip))
@@ -430,8 +488,10 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
 
   setIndexTerm(d[], symbolOrId, name, linkTitle,
     xmltree.escape(plainDocstring.docstringSummary))
+  if k == skType and nameNode.kind == nkSym:
+    d.types.strTableAdd nameNode.sym
 
-proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
+proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
   if not isVisible(nameNode): return
   var
     name = getName(d, nameNode)
@@ -440,8 +500,8 @@ proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
 
   initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
 
-  result = %{ "name": %name, "type": %($k) }
-
+  result = %{ "name": %name, "type": %($k), "line": %n.info.line,
+                 "col": %n.info.col}
   if comm != nil and comm != "":
     result["description"] = %comm
   if r.buf != nil:
@@ -491,46 +551,45 @@ proc generateDoc*(d: PDoc, n: PNode) =
   of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
   else: discard
 
-proc generateJson(d: PDoc, n: PNode, jArray: JsonNode = nil): JsonNode =
+proc add(d: PDoc; j: JsonNode) =
+  if j != nil: d.jArray.add j
+
+proc generateJson*(d: PDoc, n: PNode) =
   case n.kind
   of nkCommentStmt:
     if n.comment != nil and startsWith(n.comment, "##"):
       let stripped = n.comment.substr(2).strip
-      result = %{ "comment": %stripped }
+      d.add %{ "comment": %stripped, "line": %n.info.line,
+               "col": %n.info.col }
   of nkProcDef:
     when useEffectSystem: documentRaises(n)
-    result = genJSONItem(d, n, n.sons[namePos], skProc)
+    d.add genJsonItem(d, n, n.sons[namePos], skProc)
   of nkMethodDef:
     when useEffectSystem: documentRaises(n)
-    result = genJSONItem(d, n, n.sons[namePos], skMethod)
+    d.add genJsonItem(d, n, n.sons[namePos], skMethod)
   of nkIteratorDef:
     when useEffectSystem: documentRaises(n)
-    result = genJSONItem(d, n, n.sons[namePos], skIterator)
+    d.add genJsonItem(d, n, n.sons[namePos], skIterator)
   of nkMacroDef:
-    result = genJSONItem(d, n, n.sons[namePos], skMacro)
+    d.add genJsonItem(d, n, n.sons[namePos], skMacro)
   of nkTemplateDef:
-    result = genJSONItem(d, n, n.sons[namePos], skTemplate)
+    d.add genJsonItem(d, n, n.sons[namePos], skTemplate)
   of nkConverterDef:
     when useEffectSystem: documentRaises(n)
-    result = genJSONItem(d, n, n.sons[namePos], skConverter)
+    d.add genJsonItem(d, n, n.sons[namePos], skConverter)
   of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
     for i in countup(0, sonsLen(n) - 1):
       if n.sons[i].kind != nkCommentStmt:
         # order is always 'type var let const':
-        result = genJSONItem(d, n.sons[i], n.sons[i].sons[0],
+        d.add genJsonItem(d, n.sons[i], n.sons[i].sons[0],
                 succ(skType, ord(n.kind)-ord(nkTypeSection)))
   of nkStmtList:
-    result = if jArray != nil: jArray else: newJArray()
-
     for i in countup(0, sonsLen(n) - 1):
-      var r = generateJson(d, n.sons[i], result)
-      if r != nil:
-        result.add(r)
-
+      generateJson(d, n.sons[i])
   of nkWhenStmt:
     # generate documentation for the first branch only:
-    if not checkForFalse(n.sons[0].sons[0]) and jArray != nil:
-      discard generateJson(d, lastSon(n.sons[0]), jArray)
+    if not checkForFalse(n.sons[0].sons[0]):
+      generateJson(d, lastSon(n.sons[0]))
   else: discard
 
 proc genSection(d: PDoc, kind: TSymKind) =
@@ -592,12 +651,36 @@ proc generateIndex*(d: PDoc) =
     writeIndexFile(d[], splitFile(options.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
+    createDir(d)
+    result = d / changeFileExt(filename, ext)
+  else:
+    result = getOutFile(filename, ext)
+
 proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
   var content = genOutFile(d)
   if optStdout in gGlobalOptions:
     writeRope(stdout, content)
   else:
-    writeRope(content, getOutFile(filename, outExt), useWarning)
+    writeRope(content, getOutFile2(filename, outExt, "htmldocs"), useWarning)
+
+proc writeOutputJson*(d: PDoc, filename, outExt: string,
+                      useWarning = false) =
+  let content = %*{"orig": d.filename,
+    "nimble": getPackageName(d.filename),
+    "entries": d.jArray}
+  if optStdout in gGlobalOptions:
+    write(stdout, $content)
+  else:
+    var f: File
+    if open(f, getOutFile2(splitFile(filename).name,
+            outExt, "jsondocs"), fmWrite):
+      write(f, $content)
+      close(f)
+    else:
+      discard "fixme: error report"
 
 proc commandDoc*() =
   var ast = parseFile(gProjectMainIdx)
@@ -628,18 +711,19 @@ proc commandRst2TeX*() =
   splitter = "\\-"
   commandRstAux(gProjectFull, TexExt)
 
-proc commandJSON*() =
+proc commandJson*() =
   var ast = parseFile(gProjectMainIdx)
   if ast == nil: return
   var d = newDocumentor(gProjectFull, options.gConfigVars)
   d.hasToc = true
-  var json = generateJson(d, ast)
-  var content = rope(pretty(json))
+  generateJson(d, ast)
+  let json = d.jArray
+  let content = rope(pretty(json))
 
   if optStdout in gGlobalOptions:
     writeRope(stdout, content)
   else:
-    echo getOutFile(gProjectFull, JsonExt)
+    #echo getOutFile(gProjectFull, JsonExt)
     writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
 
 proc commandBuildIndex*() =
diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim
index 27de06811..d70d5406c 100644
--- a/compiler/docgen2.nim
+++ b/compiler/docgen2.nim
@@ -19,21 +19,36 @@ type
     module: PSym
   PGen = ref TGen
 
-proc close(p: PPassContext, n: PNode): PNode =
+template closeImpl(body: untyped) {.dirty.} =
   var g = PGen(p)
   let useWarning = sfMainModule notin g.module.flags
-  if gWholeProject or sfMainModule in g.module.flags:
-    writeOutput(g.doc, g.module.filename, HtmlExt, useWarning)
+  #echo g.module.name.s, " ", g.module.owner.id, " ", gMainPackageId
+  if (g.module.owner.id == gMainPackageId and gWholeProject) or
+    sfMainModule in g.module.flags:
+    body
     try:
       generateIndex(g.doc)
     except IOError:
       discard
 
+proc close(p: PPassContext, n: PNode): PNode =
+  closeImpl:
+    writeOutput(g.doc, g.module.filename, HtmlExt, useWarning)
+
+proc closeJson(p: PPassContext, n: PNode): PNode =
+  closeImpl:
+    writeOutputJson(g.doc, g.module.filename, ".json", useWarning)
+
 proc processNode(c: PPassContext, n: PNode): PNode =
   result = n
   var g = PGen(c)
   generateDoc(g.doc, n)
 
+proc processNodeJson(c: PPassContext, n: PNode): PNode =
+  result = n
+  var g = PGen(c)
+  generateJson(g.doc, n)
+
 proc myOpen(module: PSym): PPassContext =
   var g: PGen
   new(g)
@@ -44,6 +59,8 @@ proc myOpen(module: PSym): PPassContext =
   result = g
 
 const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close)
+const docgen2JsonPass* = makePass(open = myOpen, process = processNodeJson,
+                                  close = closeJson)
 
 proc finishDoc2Pass*(project: string) =
   discard
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index b2ee9c7f1..eb9aac490 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -754,7 +754,7 @@ proc callCCompiler*(projectfile: string) =
           "lib", quoteShell(libpath)])
     if optCompileOnly notin gGlobalOptions:
       execExternalProgram(linkCmd,
-                          if gVerbosity > 1: hintExecuting else: hintLinking)
+        if optListCmd in gGlobalOptions or gVerbosity > 1: hintExecuting else: hintLinking)
   else:
     linkCmd = ""
   if optGenScript in gGlobalOptions:
diff --git a/compiler/idgen.nim b/compiler/idgen.nim
index 906c16546..333772705 100644
--- a/compiler/idgen.nim
+++ b/compiler/idgen.nim
@@ -11,7 +11,7 @@
 
 import idents, strutils, os, options
 
-var gFrontEndId, gBackendId*: int
+var gFrontEndId*: int
 
 const
   debugIds* = false
@@ -30,10 +30,6 @@ proc getID*(): int {.inline.} =
   result = gFrontEndId
   inc(gFrontEndId)
 
-proc backendId*(): int {.inline.} =
-  result = gBackendId
-  inc(gBackendId)
-
 proc setId*(id: int) {.inline.} =
   gFrontEndId = max(gFrontEndId, id + 1)
 
@@ -49,7 +45,6 @@ proc toGid(f: string): string =
 proc saveMaxIds*(project: string) =
   var f = open(project.toGid, fmWrite)
   f.writeLine($gFrontEndId)
-  f.writeLine($gBackendId)
   f.close()
 
 proc loadMaxIds*(project: string) =
@@ -61,5 +56,4 @@ proc loadMaxIds*(project: string) =
       if f.readLine(line):
         var backEndId = parseInt(line)
         gFrontEndId = max(gFrontEndId, frontEndId)
-        gBackendId = max(gBackendId, backEndId)
     f.close()
diff --git a/compiler/installer.ini b/compiler/installer.ini
index 07fdb13b5..b802f08f1 100644
--- a/compiler/installer.ini
+++ b/compiler/installer.ini
@@ -8,7 +8,7 @@ Platforms: """
   windows: i386;amd64
   linux: i386;amd64;powerpc64;arm;sparc;mips;mipsel;powerpc;powerpc64el;arm64
   macosx: i386;amd64;powerpc64
-  solaris: i386;amd64;sparc
+  solaris: i386;amd64;sparc;sparc64
   freebsd: i386;amd64
   netbsd: i386;amd64
   openbsd: i386;amd64
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 41e42b825..a60b0cc5e 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -48,6 +48,7 @@ type
     etyNull,                  # null type
     etyProc,                  # proc type
     etyBool,                  # bool type
+    etySeq,                   # Nim seq or string type
     etyInt,                   # JavaScript's int
     etyFloat,                 # JavaScript's float
     etyString,                # JavaScript's string
@@ -156,15 +157,18 @@ proc mapType(typ: PType): TJSTypeKind =
   of tyBool: result = etyBool
   of tyFloat..tyFloat128: result = etyFloat
   of tySet: result = etyObject # map a set to a table
-  of tyString, tySequence: result = etyInt # little hack to get right semantics
+  of tyString, tySequence: result = etySeq
   of tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, tyBigNum,
      tyVarargs:
     result = etyObject
   of tyNil: result = etyNull
   of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvocation,
      tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor,
-     tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses:
+     tyExpr, tyStmt, tyTypeDesc, tyTypeClasses, tyVoid:
     result = etyNone
+  of tyStatic:
+    if t.n != nil: result = mapType(lastSon t)
+    else: result = etyNone
   of tyProc: result = etyProc
   of tyCString: result = etyString
 
@@ -817,7 +821,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
     addf(p.body, "$#[$#] = chr($#);$n", [a.rdLoc, b.rdLoc, c.rdLoc])
     return
 
-  let xtyp = mapType(p, x.typ)
+  var xtyp = mapType(p, x.typ)
 
   if x.kind == nkHiddenDeref and x.sons[0].kind == nkCall and xtyp != etyObject:
     gen(p, x.sons[0], a)
@@ -829,7 +833,18 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
 
   gen(p, y, b)
 
+  # we don't care if it's an etyBaseIndex (global) of a string, it's
+  # still a string that needs to be copied properly:
+  if x.typ.skipTypes(abstractInst).kind in {tySequence, tyString}:
+    xtyp = etySeq
   case xtyp
+  of etySeq:
+    if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
+      addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
+    else:
+      useMagic(p, "nimCopy")
+      addf(p.body, "$1 = nimCopy(null, $2, $3);$n",
+           [a.rdLoc, b.res, genTypeInfo(p, y.typ)])
   of etyObject:
     if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
       addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
@@ -1049,6 +1064,8 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
       else: internalError(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)
 
 proc thisParam(p: PProc; typ: PType): PType =
@@ -1215,11 +1232,13 @@ proc genOtherArg(p: PProc; n: PNode; i: int; typ: PType;
     genArgNoParam(p, it, r)
   else:
     genArg(p, it, paramType.sym, r)
+  inc generated
 
 proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
                     r: var TCompRes) =
   var i = 0
   var j = 1
+  r.kind = resExpr
   while i < pat.len:
     case pat[i]
     of '@':
@@ -1233,10 +1252,18 @@ proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
       genOtherArg(p, n, j, typ, generated, r)
       inc j
       inc i
+    of '\31':
+      # unit separator
+      add(r.res, "#")
+      inc i
+    of '\29':
+      # group separator
+      add(r.res, "@")
+      inc i
     else:
       let start = i
       while i < pat.len:
-        if pat[i] notin {'@', '#'}: inc(i)
+        if pat[i] notin {'@', '#', '\31', '\29'}: inc(i)
         else: break
       if i - 1 >= start:
         add(r.res, substr(pat, start, i - 1))
@@ -1403,6 +1430,12 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
       result = putToSeq("null", indirect)
   of tySequence, tyString, tyCString, tyPointer, tyProc:
     result = putToSeq("null", indirect)
+  of tyStatic:
+    if t.n != nil:
+      result = createVar(p, lastSon t, indirect)
+    else:
+      internalError("createVar: " & $t.kind)
+      result = nil
   else:
     internalError("createVar: " & $t.kind)
     result = nil
@@ -1418,7 +1451,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
     discard mangleName(v, p.target)
     gen(p, n, a)
     case mapType(p, v.typ)
-    of etyObject:
+    of etyObject, etySeq:
       if needsNoCopy(p, n):
         s = a.res
       else:
@@ -1557,8 +1590,16 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
   of tyEnum, tyOrdinal:
     gen(p, n.sons[1], r)
     useMagic(p, "cstrToNimstr")
+    var offset = ""
+    if t.kind == tyEnum:
+      let firstFieldOffset = t.n.sons[0].sym.position
+      if firstFieldOffset < 0:
+        offset = "+" & $(-firstFieldOffset)
+      elif firstFieldOffset > 0:
+        offset = "-" & $firstFieldOffset
+
     r.kind = resExpr
-    r.res = "cstrToNimstr($1.node.sons[$2].name)" % [genTypeInfo(p, t), r.res]
+    r.res = "cstrToNimstr($1.node.sons[$2$3].name)" % [genTypeInfo(p, t), r.res, rope(offset)]
   else:
     # XXX:
     internalError(n.info, "genRepr: Not implemented")
@@ -1678,8 +1719,9 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
     else:
       if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
       else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)")
-  of mSetLengthStr: binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0" | "")
-  of mSetLengthSeq: binaryExpr(p, n, r, "", "$1.length = $2" | "")
+  of mSetLengthStr:
+    binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0" | "$1 = substr($1, 0, $2)")
+  of mSetLengthSeq: binaryExpr(p, n, r, "", "$1.length = $2" | "$1 = array_slice($1, 0, $2)")
   of mCard: unaryExpr(p, n, r, "SetCard", "SetCard($1)")
   of mLtSet: binaryExpr(p, n, r, "SetLt", "SetLt($1, $2)")
   of mLeSet: binaryExpr(p, n, r, "SetLe", "SetLe($1, $2)")
@@ -1689,8 +1731,31 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
   of mMinusSet: binaryExpr(p, n, r, "SetMinus", "SetMinus($1, $2)")
   of mIncl: binaryExpr(p, n, r, "", "$1[$2] = true")
   of mExcl: binaryExpr(p, n, r, "", "delete $1[$2]" | "unset $1[$2]")
-  of mInSet: binaryExpr(p, n, r, "", "($1[$2] != undefined)" | "isset($1[$2])")
+  of mInSet:
+    if p.target == targetJS:
+      binaryExpr(p, n, r, "", "($1[$2] != undefined)")
+    else:
+      let s = n.sons[1]
+      if s.kind == nkCurly:
+        var a, b, x: TCompRes
+        gen(p, n.sons[2], x)
+        r.res = rope("(")
+        r.kind = resExpr
+        for i in countup(0, sonsLen(s) - 1):
+          if i > 0: add(r.res, " || ")
+          var it = s.sons[i]
+          if it.kind == nkRange:
+            gen(p, it.sons[0], a)
+            gen(p, it.sons[1], b)
+            addf(r.res, "($1 >= $2 && $1 <= $3)", [x.res, a.res, b.res,])
+          else:
+            gen(p, it, a)
+            addf(r.res, "($1 == $2)", [x.res, a.res])
+        add(r.res, ")")
+      else:
+        binaryExpr(p, n, r, "", "isset($1[$2])")
   of mNewSeq: genNewSeq(p, n)
+  of mNewSeqOfCap: unaryExpr(p, n, r, "", "[]" | "array()")
   of mOf: genOf(p, n, r)
   of mReset: genReset(p, n)
   of mEcho: genEcho(p, n, r)
@@ -1989,7 +2054,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
     if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone):
       genMagic(p, n, r)
     elif n.sons[0].kind == nkSym and sfInfixCall in n.sons[0].sym.flags and
-        n.len >= 2:
+        n.len >= 1:
       genInfixCall(p, n, r)
     else:
       genCall(p, n, r)
diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim
index 8d109e48a..cf1679ee4 100644
--- a/compiler/jstypes.nim
+++ b/compiler/jstypes.nim
@@ -165,4 +165,7 @@ proc genTypeInfo(p: PProc, typ: PType): Rope =
   of tyEnum: genEnumInfo(p, t, result)
   of tyObject: genObjectInfo(p, t, result)
   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 & ')')
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index 8b201431e..0a96ed0ba 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -735,7 +735,8 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
       if  c == '\226' and
           buf[pos+1] == '\128' and
           buf[pos+2] == '\147':  # It's a 'magic separator' en-dash Unicode
-        if buf[pos + magicIdentSeparatorRuneByteWidth] notin SymChars:
+        if buf[pos + magicIdentSeparatorRuneByteWidth] notin SymChars or
+            isMagicIdentSeparatorRune(buf, pos+magicIdentSeparatorRuneByteWidth) or pos == L.bufpos:
           lexMessage(L, errInvalidToken, "–")
           break
         inc(pos, magicIdentSeparatorRuneByteWidth)
@@ -747,7 +748,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
       h = h !& ord(c)
       inc(pos)
     of '_':
-      if buf[pos+1] notin SymChars:
+      if buf[pos+1] notin SymChars or isMagicIdentSeparatorRune(buf, pos+1):
         lexMessage(L, errInvalidToken, "_")
         break
       inc(pos)
@@ -1056,7 +1057,8 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
       inc(L.bufpos)
     of '_':
       inc(L.bufpos)
-      if L.buf[L.bufpos] notin SymChars:
+      if L.buf[L.bufpos] notin SymChars+{'_'} and not
+          isMagicIdentSeparatorRune(L.buf, L.bufpos):
         tok.tokType = tkSymbol
         tok.ident = getIdent("_")
       else:
@@ -1077,6 +1079,9 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
       tok.tokType = tkCharLit
     of '0'..'9':
       getNumber(L, tok)
+      let c = L.buf[L.bufpos]
+      if c in SymChars+{'_'}:
+        lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
     else:
       if c in OpChars:
         getOperator(L, tok)
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index 962c28613..ba2358b86 100644
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -153,7 +153,8 @@ proc ensureNoMissingOrUnusedSymbols(scope: PScope) =
       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:
+        if s.typ != nil and tfImplicitTypeParam notin s.typ.flags and
+           s.typ.kind != tyGenericParam:
           message(s.info, hintXDeclaredButNotUsed, getSymRepr(s))
     s = nextIter(it, scope.symbols)
 
diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim
index 7a5c7f44b..cdea2a4ff 100644
--- a/compiler/lowerings.nim
+++ b/compiler/lowerings.nim
@@ -471,6 +471,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
       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)
       objType.addField(fieldB)
diff --git a/compiler/main.nim b/compiler/main.nim
index b1b9006bd..0db66b53e 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -46,10 +46,11 @@ proc commandCheck =
   rodPass()
   compileProject()
 
-proc commandDoc2 =
+proc commandDoc2(json: bool) =
   msgs.gErrorMax = high(int)  # do not stop after first error
   semanticPasses()
-  registerPass(docgen2Pass)
+  if json: registerPass(docgen2JsonPass)
+  else: registerPass(docgen2Pass)
   #registerPass(cleanupPass())
   compileProject()
   finishDoc2Pass(gProjectName)
@@ -281,7 +282,7 @@ proc mainCommand* =
     gCmd = cmdDoc
     loadConfigs(DocConfig)
     defineSymbol("nimdoc")
-    commandDoc2()
+    commandDoc2(false)
   of "rst2html":
     gCmd = cmdRst2html
     loadConfigs(DocConfig)
@@ -296,7 +297,13 @@ proc mainCommand* =
     loadConfigs(DocConfig)
     wantMainModule()
     defineSymbol("nimdoc")
-    commandJSON()
+    commandJson()
+  of "jsondoc2":
+    gCmd = cmdDoc
+    loadConfigs(DocConfig)
+    wantMainModule()
+    defineSymbol("nimdoc")
+    commandDoc2(true)
   of "buildindex":
     gCmd = cmdDoc
     loadConfigs(DocConfig)
diff --git a/compiler/modules.nim b/compiler/modules.nim
index 8ac964321..8df300f5f 100644
--- a/compiler/modules.nim
+++ b/compiler/modules.nim
@@ -29,6 +29,10 @@ var
   gMemCacheData*: seq[TModuleInMemory] = @[]
     ## XXX: we should implement recycling of file IDs
     ## if the user keeps renaming modules, the file IDs will keep growing
+  gFuzzyGraphChecking*: bool # nimsuggest uses this. XXX figure out why.
+  packageSyms: TStrTable
+
+initStrTable(packageSyms)
 
 proc getModule*(fileIdx: int32): PSym =
   if fileIdx >= 0 and fileIdx < gCompiledModules.len:
@@ -90,6 +94,7 @@ proc resetAllModules* =
     if gCompiledModules[i] != nil:
       resetModule(i.int32)
   resetPackageCache()
+  initStrTable(packageSyms)
   # for m in cgenModules(): echo "CGEN MODULE FOUND"
 
 proc resetAllModulesHard* =
@@ -97,6 +102,7 @@ proc resetAllModulesHard* =
   gCompiledModules.setLen 0
   gMemCacheData.setLen 0
   magicsys.resetSysTypes()
+  initStrTable(packageSyms)
   # XXX
   #gOwners = @[]
 
@@ -105,12 +111,16 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile =
     resetModule(fileIdx)
     return Yes
 
-  if gMemCacheData[fileIdx].needsRecompile != Maybe:
-    return gMemCacheData[fileIdx].needsRecompile
+  if gFuzzyGraphChecking:
+    if gMemCacheData[fileIdx].needsRecompile != Maybe:
+      return gMemCacheData[fileIdx].needsRecompile
+  else:
+    # cycle detection: We claim that a cycle does no harm.
+    if gMemCacheData[fileIdx].needsRecompile == Probing:
+      return No
 
-  if optForceFullMake in gGlobalOptions or
-     hashChanged(fileIdx):
-       markDirty
+  if optForceFullMake in gGlobalOptions or hashChanged(fileIdx):
+    markDirty()
 
   if gMemCacheData[fileIdx].deps != nil:
     gMemCacheData[fileIdx].needsRecompile = Probing
@@ -118,7 +128,7 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile =
       let d = checkDepMem(dep)
       if d in {Yes, Recompiled}:
         # echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
-        markDirty
+        markDirty()
 
   gMemCacheData[fileIdx].needsRecompile = No
   return No
@@ -135,8 +145,16 @@ proc newModule(fileIdx: int32): PSym =
     rawMessage(errInvalidModuleName, result.name.s)
 
   result.info = newLineInfo(fileIdx, 1, 1)
-  result.owner = newSym(skPackage, getIdent(getPackageName(filename)), nil,
-                        result.info)
+  let pack = getIdent(getPackageName(filename))
+  var packSym = packageSyms.strTableGet(pack)
+  if packSym == nil:
+    let pck = getPackageName(filename)
+    let pck2 = if pck.len > 0: pck else: "unknown"
+    packSym = newSym(skPackage, getIdent(pck2), nil, result.info)
+    initStrTable(packSym.tab)
+    packageSyms.strTableAdd(packSym)
+
+  result.owner = packSym
   result.position = fileIdx
 
   growCache gMemCacheData, fileIdx
@@ -146,6 +164,11 @@ proc newModule(fileIdx: int32): PSym =
   incl(result.flags, sfUsed)
   initStrTable(result.tab)
   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)
+  # strTableIncl() for error corrections:
+  discard strTableIncl(packSym.tab, result)
 
 proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym =
   result = getModule(fileIdx)
@@ -184,8 +207,8 @@ proc importModule*(s: PSym, fileIdx: int32): PSym {.procvar.} =
   # this is called by the semantic checking phase
   result = compileModule(fileIdx, {})
   if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx)
-  if sfSystemModule in result.flags:
-    localError(result.info, errAttemptToRedefine, result.name.s)
+  #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
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index ce9d8c8b6..83914753f 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -502,8 +502,6 @@ type
   ESuggestDone* = object of Exception
 
 const
-  ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic,
-    hintQuitCalled}
   NotesVerbosity*: array[0..3, TNoteKinds] = [
     {low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
                                          warnProveField, warnProveIndex,
@@ -520,7 +518,6 @@ const
                                          warnGcUnsafe,
                                          hintPath,
                                          hintDependency,
-                                         hintExecuting,
                                          hintCodeBegin, hintCodeEnd,
                                          hintSource, hintStackTrace,
                                          hintGCStats},
@@ -531,6 +528,8 @@ const
   InvalidFileIDX* = int32(-1)
 
 var
+  ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic,
+    hintQuitCalled, hintExecuting}
   filenameToIndexTbl = initTable[string, int32]()
   fileInfos*: seq[TFileInfo] = @[]
   systemFileIdx*: int32
@@ -621,6 +620,7 @@ var
   gHintCounter*: int = 0
   gWarnCounter*: int = 0
   gErrorMax*: int = 1         # stop after gErrorMax errors
+  gMainPackageNotes*: TNoteKinds = NotesVerbosity[1]
 
 proc unknownLineInfo*(): TLineInfo =
   result.line = int16(-1)
diff --git a/compiler/nimfix/pretty.nim b/compiler/nimfix/pretty.nim
index 1123afb9e..8ba922927 100644
--- a/compiler/nimfix/pretty.nim
+++ b/compiler/nimfix/pretty.nim
@@ -66,7 +66,7 @@ proc beautifyName(s: string, k: TSymKind): string =
              ]:
       result.add s[i]
     else:
-      result.add toUpper(s[i])
+      result.add toUpperAscii(s[i])
   of skConst, skEnumField:
     # for 'const' we keep how it's spelt; either upper case or lower case:
     result.add s[0]
@@ -74,7 +74,7 @@ proc beautifyName(s: string, k: TSymKind): string =
     # as a special rule, don't transform 'L' to 'l'
     if s.len == 1 and s[0] == 'L': result.add 'L'
     elif '_' in s: result.add(s[i])
-    else: result.add toLower(s[0])
+    else: result.add toLowerAscii(s[0])
   inc i
   while i < s.len:
     if s[i] == '_':
@@ -85,9 +85,9 @@ proc beautifyName(s: string, k: TSymKind): string =
         result.add s[i]
       else:
         inc i
-        result.add toUpper(s[i])
+        result.add toUpperAscii(s[i])
     elif allUpper:
-      result.add toLower(s[i])
+      result.add toLowerAscii(s[i])
     else:
       result.add s[i]
     inc i
diff --git a/compiler/options.nim b/compiler/options.nim
index 7797a4c82..dbd8ca2b9 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -151,6 +151,7 @@ const
 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'
@@ -211,9 +212,7 @@ proc setDefaultLibpath*() =
 
     # Special rule to support other tools (nimble) which import the compiler
     # modules and make use of them.
-    let realNimPath = # Make sure we expand the symlink
-      if symlinkExists(findExe("nim")): expandSymlink(findExe("nim"))
-      else: findExe("nim")
+    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
@@ -221,7 +220,7 @@ proc setDefaultLibpath*() =
       libpath = parentNimLibPath
 
 proc canonicalizePath*(path: string): string =
-  when not FileSystemCaseSensitive: result = path.expandFilename.toLower
+  when not FileSystemCaseSensitive: result = path.expandFilename.toLowerAscii
   else: result = path.expandFilename
 
 proc shortenDir*(dir: string): string =
@@ -240,6 +239,8 @@ proc removeTrailingDirSep*(path: string): string =
   else:
     result = path
 
+include packagehandling
+
 proc getNimcacheDir*: string =
   result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir /
                                                          genSubDir
@@ -259,54 +260,6 @@ proc pathSubs*(p, config: string): string =
   if '~' in result:
     result = result.replace("~", home)
 
-template newPackageCache(): expr =
-  newStringTable(when FileSystemCaseSensitive:
-                   modeCaseInsensitive
-                 else:
-                   modeCaseSensitive)
-
-var packageCache = newPackageCache()
-
-proc resetPackageCache*() = packageCache = newPackageCache()
-
-iterator myParentDirs(p: string): string =
-  # XXX os's parentDirs is stupid (multiple yields) and triggers an old bug...
-  var current = p
-  while true:
-    current = current.parentDir
-    if current.len == 0: break
-    yield current
-
-proc getPackageName*(path: string): string =
-  var parents = 0
-  block packageSearch:
-    for d in myParentDirs(path):
-      if packageCache.hasKey(d):
-        #echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name
-        return packageCache[d]
-      inc parents
-      for file in walkFiles(d / "*.nimble"):
-        result = file.splitFile.name
-        break packageSearch
-      for file in walkFiles(d / "*.babel"):
-        result = file.splitFile.name
-        break packageSearch
-  # we also store if we didn't find anything:
-  if result.isNil: result = ""
-  for d in myParentDirs(path):
-    #echo "set cache ", d, " |", result, "|", parents
-    packageCache[d] = result
-    dec parents
-    if parents <= 0: break
-
-proc withPackageName*(path: string): string =
-  let x = path.getPackageName
-  if x.len == 0:
-    result = path
-  else:
-    let (p, file, ext) = path.splitFile
-    result = (p / (x & '_' & file)) & ext
-
 proc toGeneratedFile*(path, ext: string): string =
   ## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"
   var (head, tail) = splitPath(path)
@@ -374,17 +327,25 @@ proc rawFindFile2(f: string): string =
     it = PStrEntry(it.next)
   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]
+      if ov.len > 0: result = ov
+
 proc findFile*(f: string): string {.procvar.} =
   if f.isAbsolute:
     result = if f.existsFile: f else: ""
   else:
     result = f.rawFindFile
     if result.len == 0:
-      result = f.toLower.rawFindFile
+      result = f.toLowerAscii.rawFindFile
       if result.len == 0:
         result = f.rawFindFile2
         if result.len == 0:
-          result = f.toLower.rawFindFile2
+          result = f.toLowerAscii.rawFindFile2
+  patchModule()
 
 proc findModule*(modulename, currentModule: string): string =
   # returns path to module
@@ -403,6 +364,7 @@ proc findModule*(modulename, currentModule: string): string =
   result = currentPath / m
   if not existsFile(result):
     result = findFile(m)
+  patchModule()
 
 proc libCandidates*(s: string, dest: var seq[string]) =
   var le = strutils.find(s, '(')
diff --git a/compiler/packagehandling.nim b/compiler/packagehandling.nim
new file mode 100644
index 000000000..c42a4d763
--- /dev/null
+++ b/compiler/packagehandling.nim
@@ -0,0 +1,56 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2016 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+iterator myParentDirs(p: string): string =
+  # XXX os's parentDirs is stupid (multiple yields) and triggers an old bug...
+  var current = p
+  while true:
+    current = current.parentDir
+    if current.len == 0: break
+    yield current
+
+template newPackageCache(): expr =
+  newStringTable(when FileSystemCaseSensitive:
+                   modeCaseInsensitive
+                 else:
+                   modeCaseSensitive)
+
+var packageCache = newPackageCache()
+
+proc resetPackageCache*() = packageCache = newPackageCache()
+
+proc getPackageName*(path: string): string =
+  var parents = 0
+  block packageSearch:
+    for d in myParentDirs(path):
+      if packageCache.hasKey(d):
+        #echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name
+        return packageCache[d]
+      inc parents
+      for file in walkFiles(d / "*.nimble"):
+        result = file.splitFile.name
+        break packageSearch
+      for file in walkFiles(d / "*.babel"):
+        result = file.splitFile.name
+        break packageSearch
+  # we also store if we didn't find anything:
+  if result.isNil: result = ""
+  for d in myParentDirs(path):
+    #echo "set cache ", d, " |", result, "|", parents
+    packageCache[d] = result
+    dec parents
+    if parents <= 0: break
+
+proc withPackageName*(path: string): string =
+  let x = path.getPackageName
+  if x.len == 0:
+    result = path
+  else:
+    let (p, file, ext) = path.splitFile
+    result = (p / (x & '_' & file)) & ext
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 6132216e1..8b20b56db 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -686,11 +686,19 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
   #|       | '{' optInd indexExprList optPar '}'
   #|       | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax
   result = r
+
+  template somePar() =
+    if p.tok.strongSpaceA > 0:
+      if p.strongSpaces:
+        break
+      else:
+        parMessage(p, warnDeprecated,
+          "a [b] will be parsed as command syntax; spacing")
   while p.tok.indent < 0 or
        (p.tok.tokType == tkDot and p.tok.indent >= baseIndent):
     case p.tok.tokType
     of tkParLe:
-      if p.strongSpaces and p.tok.strongSpaceA > 0: break
+      somePar()
       result = namedParams(p, result, nkCall, tkParRi)
       if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
         result.kind = nkObjConstr
@@ -705,10 +713,10 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
       result = dotExpr(p, result)
       result = parseGStrLit(p, result)
     of tkBracketLe:
-      if p.strongSpaces and p.tok.strongSpaceA > 0: break
+      somePar()
       result = namedParams(p, result, nkBracketExpr, tkBracketRi)
     of tkCurlyLe:
-      if p.strongSpaces and p.tok.strongSpaceA > 0: break
+      somePar()
       result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
     of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType:
       if p.inPragma == 0:
diff --git a/compiler/passaux.nim b/compiler/passaux.nim
index 9b9fdca4e..d4361a671 100644
--- a/compiler/passaux.nim
+++ b/compiler/passaux.nim
@@ -24,7 +24,7 @@ proc verboseProcess(context: PPassContext, n: PNode): PNode =
     # 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.gBackendId)
+    message(n.info, hintProcessing, $idgen.gFrontendId)
 
 const verbosePass* = makePass(open = verboseOpen, process = verboseProcess)
 
diff --git a/compiler/patterns.nim b/compiler/patterns.nim
index 2336e44e7..09b8d3305 100644
--- a/compiler/patterns.nim
+++ b/compiler/patterns.nim
@@ -75,7 +75,7 @@ proc checkTypes(c: PPatternContext, p: PSym, n: PNode): bool =
     result = matchNodeKinds(p.constraint, n)
     if not result: return
   if isNil(n.typ):
-    result = p.typ.kind in {tyEmpty, tyStmt}
+    result = p.typ.kind in {tyVoid, tyStmt}
   else:
     result = sigmatch.argtypeMatches(c.c, p.typ, n.typ)
 
diff --git a/compiler/platform.nim b/compiler/platform.nim
index dc414bfeb..36ec10477 100644
--- a/compiler/platform.nim
+++ b/compiler/platform.nim
@@ -159,7 +159,7 @@ type
                      # alias conditionals to condsyms (end of module).
     cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64,
     cpuPowerpc64el, cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuMipsel,
-    cpuArm, cpuArm64, cpuJS, cpuNimrodVM, cpuAVR, cpuMSP430
+    cpuArm, cpuArm64, cpuJS, cpuNimrodVM, cpuAVR, cpuMSP430, cpuSparc64
 
 type
   TEndian* = enum
@@ -187,7 +187,8 @@ const
     (name: "js", intSize: 32, endian: bigEndian,floatSize: 64,bit: 32),
     (name: "nimrodvm", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
     (name: "avr", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16),
-    (name: "msp430", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16)]
+    (name: "msp430", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16),
+    (name: "sparc64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64)]
 
 var
   targetCPU*, hostCPU*: TSystemCPU
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index dc618d9aa..d7d1ed838 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -63,11 +63,12 @@ const
     wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
     wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims}
   constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
-    wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims}
+    wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims,
+    wIntDefine, wStrDefine}
   letPragmas* = varPragmas
   procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
                       wThread, wRaises, wLocks, wTags, wGcSafe}
-  allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
+  allRoutinePragmas* = methodPragmas + iteratorPragmas + lambdaPragmas
 
 proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
 # implementation
@@ -898,6 +899,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
       of wBase:
         noVal(it)
         sym.flags.incl sfBase
+      of wIntDefine:
+        sym.magic = mIntDefine
+      of wStrDefine:
+        sym.magic = mStrDefine
       else: invalidPragma(it)
     else: invalidPragma(it)
 
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index e1db327f4..0e733d643 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -704,7 +704,10 @@ proc gcase(g: var TSrcGen, n: PNode) =
 proc gproc(g: var TSrcGen, n: PNode) =
   var c: TContext
   if n.sons[namePos].kind == nkSym:
-    put(g, tkSymbol, renderDefinitionName(n.sons[namePos].sym))
+    let s = n.sons[namePos].sym
+    put(g, tkSymbol, renderDefinitionName(s))
+    if sfGenSym in s.flags:
+      put(g, tkIntLit, $s.id)
   else:
     gsub(g, n.sons[namePos])
 
@@ -798,7 +801,8 @@ proc gident(g: var TSrcGen, n: PNode) =
   else:
     t = tkOpr
   put(g, t, s)
-  if n.kind == nkSym and renderIds in g.flags: put(g, tkIntLit, $n.sym.id)
+  if n.kind == nkSym and (renderIds in g.flags or sfGenSym in n.sym.flags):
+    put(g, tkIntLit, $n.sym.id)
 
 proc doParamsAux(g: var TSrcGen, params: PNode) =
   if params.len > 1:
diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim
index 91f93d279..945c94bc6 100644
--- a/compiler/rodutils.nim
+++ b/compiler/rodutils.nim
@@ -21,7 +21,7 @@ proc toStrMaxPrecision*(f: BiggestFloat): string =
     if f > 0.0: result = "INF"
     else: result = "-INF"
   else:
-    var buf: array [0..80, char]
+    var buf: array[0..80, char]
     c_sprintf(buf, "%#.16e", f)
     result = $buf
 
diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim
index d04fd5231..833444788 100644
--- a/compiler/scriptconfig.nim
+++ b/compiler/scriptconfig.nim
@@ -13,10 +13,10 @@
 import
   ast, modules, passes, passaux, condsyms,
   options, nimconf, lists, sem, semdata, llstream, vm, vmdef, commands, msgs,
-  os, times, osproc
+  os, times, osproc, wordrecg, strtabs
 
 # we support 'cmpIgnoreStyle' natively for efficiency:
-from strutils import cmpIgnoreStyle
+from strutils import cmpIgnoreStyle, contains
 
 proc listDirs(a: VmArgs, filter: set[PathComponent]) =
   let dir = getString(a, 0)
@@ -116,7 +116,20 @@ proc setupVM*(module: PSym; scriptName: string): PEvalContext =
     setResult(a, options.command)
   cbconf switch:
     processSwitch(a.getString 0, a.getString 1, passPP, unknownLineInfo())
-
+  cbconf hintImpl:
+    processSpecificNote(a.getString 0, wHint, passPP, unknownLineInfo(),
+      a.getString 1)
+  cbconf warningImpl:
+    processSpecificNote(a.getString 0, wWarning, passPP, unknownLineInfo(),
+      a.getString 1)
+  cbconf patchFile:
+    let key = a.getString(0) & "_" & a.getString(1)
+    var val = a.getString(2).addFileExt(NimExt)
+    if {'$', '~'} in val:
+      val = pathSubs(val, vthisDir)
+    elif not isAbsolute(val):
+      val = vthisDir / val
+    gModuleOverrides[key] = val
 
 proc runNimScript*(scriptName: string; freshDefines=true) =
   passes.gIncludeFile = includeModule
diff --git a/compiler/sem.nim b/compiler/sem.nim
index a8ec2229f..7db4ae47e 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -59,8 +59,7 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode;
   # templates perform some quick check whether the cursor is actually in
   # the generic or template.
   when defined(nimsuggest):
-    assert gCmd == cmdIdeTools
-    if requiresCheck:
+    if gCmd == cmdIdeTools and requiresCheck:
       #if optIdeDebug in gGlobalOptions:
       #  echo "passing to safeSemExpr: ", renderTree(n)
       discard safeSemExpr(c, n)
@@ -165,7 +164,7 @@ proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
   result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info)
 
 proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
-  proc `$`(kind: TSymKind): string = substr(system.`$`(kind), 2).toLower
+  proc `$`(kind: TSymKind): string = substr(system.`$`(kind), 2).toLowerAscii
 
   # like newSymS, but considers gensym'ed symbols
   if n.kind == nkSym:
@@ -307,6 +306,13 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
 
 include hlo, seminst, semcall
 
+when false:
+  # hopefully not required:
+  proc resetSemFlag(n: PNode) =
+    excl n.flags, nfSem
+    for i in 0 ..< n.safeLen:
+      resetSemFlag(n[i])
+
 proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
                        flags: TExprFlags): PNode =
   ## Semantically check the output of a macro.
@@ -320,6 +326,8 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
   c.friendModules.add(s.owner.getModule)
 
   result = n
+  excl(n.flags, nfSem)
+  #resetSemFlag n
   if s.typ.sons[0] == nil:
     result = semStmt(c, result)
   else:
@@ -409,9 +417,6 @@ proc myOpen(module: PSym): PPassContext =
   c.importTable.addSym(module) # a module knows itself
   if sfSystemModule in module.flags:
     magicsys.systemModule = module # set global variable!
-  else:
-    c.importTable.addSym magicsys.systemModule # import the "System" identifier
-    importAllSymbols(c, magicsys.systemModule)
   c.topLevelScope = openScope(c)
   # don't be verbose unless the module belongs to the main package:
   if module.owner.id == gMainPackageId:
@@ -425,7 +430,29 @@ proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
   result = myOpen(module)
   for m in items(rd.methods): methodDef(m, true)
 
+proc isImportSystemStmt(n: PNode): bool =
+  if magicsys.systemModule == nil: return false
+  case n.kind
+  of nkImportStmt:
+    for x in n:
+      let f = checkModuleName(x)
+      if f == magicsys.systemModule.info.fileIndex:
+        return true
+  of nkImportExceptStmt, nkFromStmt:
+    let f = checkModuleName(n[0])
+    if f == magicsys.systemModule.info.fileIndex:
+      return true
+  else: discard
+
 proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
+  if c.topStmts == 0 and not isImportSystemStmt(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)
+      inc c.topStmts
+  else:
+    inc c.topStmts
   if sfNoForward in c.module.flags:
     result = semAllTypeSections(c, n)
   else:
diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim
index a1e209263..9702128ba 100644
--- a/compiler/semasgn.nim
+++ b/compiler/semasgn.nim
@@ -183,7 +183,7 @@ proc newSeqCall(c: PContext; x, y: PNode): PNode =
 
 proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
   case t.kind
-  of tyNone, tyEmpty: discard
+  of tyNone, tyEmpty, tyVoid: discard
   of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString,
       tyPtr, tyString, tyRef:
     defaultOp(c, t, body, x, y)
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 65aa5fd58..87a34ca4a 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -69,7 +69,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
     #  gDebug = true
     matches(c, n, orig, z)
     if errors != nil:
-      errors.safeAdd(sym)
+      errors.safeAdd((sym, int z.mutabilityProblem))
       if z.errors != nil:
         for err in z.errors:
           errors.add(err)
@@ -111,7 +111,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
   let proto = describeArgs(c, n, 1, preferName)
 
   var prefer = preferName
-  for err in errors:
+  for err, mut in items(errors):
     var errProto = ""
     let n = err.typ.n
     for i in countup(1, n.len - 1):
@@ -123,18 +123,21 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
     if errProto == proto:
       prefer = preferModuleInfo
       break
+
   # now use the information stored in 'prefer' to produce a nice error message:
   var result = msgKindToString(errTypeMismatch)
   add(result, describeArgs(c, n, 1, prefer))
   add(result, ')')
   var candidates = ""
-  for err in errors:
+  for err, mut in items(errors):
     if err.kind in routineKinds and err.ast != nil:
       add(candidates, renderTree(err.ast,
             {renderNoBody, renderNoComments,renderNoPragmas}))
     else:
       add(candidates, err.getProcHeader(prefer))
     add(candidates, "\n")
+    if mut != 0 and mut < n.len:
+      add(candidates, "for a 'var' type a variable needs to be passed, but '" & renderTree(n[mut]) & "' is immutable\n")
   if candidates != "":
     add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
   if c.compilesContextId > 0 and optReportConceptFailures in gGlobalOptions:
@@ -142,6 +145,20 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
   else:
     localError(n.info, errGenerated, result)
 
+proc bracketNotFoundError(c: PContext; n: PNode) =
+  var errors: CandidateErrors = @[]
+  var o: TOverloadIter
+  let headSymbol = n[0]
+  var symx = initOverloadIter(o, c, headSymbol)
+  while symx != nil:
+    if symx.kind in routineKinds:
+      errors.add((symx, 0))
+    symx = nextOverloadIter(o, c, headSymbol)
+  if errors.len == 0:
+    localError(n.info, "could not resolve: " & $n)
+  else:
+    notFoundError(c, n, errors)
+
 proc resolveOverloads(c: PContext, n, orig: PNode,
                       filter: TSymKinds;
                       errors: var CandidateErrors): TCandidate =
@@ -158,8 +175,6 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
   template pickBest(headSymbol) =
     pickBestCandidate(c, headSymbol, n, orig, initialBinding,
                       filter, result, alt, errors)
-
-
   pickBest(f)
 
   let overloadsState = result.state
@@ -230,7 +245,6 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
         #notFoundError(c, n, errors)
 
       return
-
   if alt.state == csMatch and cmpCandidates(result, alt) == 0 and
       not sameMethodDispatcher(result.calleeSym, alt.calleeSym):
     internalAssert result.state == csMatch
@@ -299,8 +313,7 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
   var finalCallee = x.calleeSym
   markUsed(n.sons[0].info, finalCallee)
   styleCheckUse(n.sons[0].info, finalCallee)
-  if finalCallee.ast == nil:
-    internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
+  assert finalCallee.ast != nil
   if x.hasFauxMatch:
     result = x.call
     result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
@@ -319,12 +332,12 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
       # are added as normal params.
       for s in instantiateGenericParamList(c, gp, x.bindings):
         case s.kind
-          of skConst:
-            x.call.add s.ast
-          of skType:
-            x.call.add newSymNode(s, n.info)
-          else:
-            internalAssert false
+        of skConst:
+          x.call.add s.ast
+        of skType:
+          x.call.add newSymNode(s, n.info)
+        else:
+          internalAssert false
 
   result = x.call
   instGenericConvertersSons(c, result, x)
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 91a1ebf86..30b6e261d 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -99,11 +99,12 @@ type
     unknownIdents*: IntSet     # ids of all unknown identifiers to prevent
                                # naming it multiple times
     generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile
+    topStmts*: int # counts the number of encountered top level statements
     lastGenericIdx*: int      # used for the generics stack
     hloLoopDetector*: int     # used to prevent endless loops in the HLO
     inParallelStmt*: int
     instTypeBoundOp*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo;
-                            op: TTypeAttachedOp): PSym {.nimcall.}
+                            op: TTypeAttachedOp; col: int): PSym {.nimcall.}
     selfName*: PIdent
     signatures*: TStrTable
 
diff --git a/compiler/semdestruct.nim b/compiler/semdestruct.nim
index 1261dd460..18a1c262f 100644
--- a/compiler/semdestruct.nim
+++ b/compiler/semdestruct.nim
@@ -139,6 +139,7 @@ proc instantiateDestructor(c: PContext, typ: PType): PType =
   t = t.skipTypes({tyGenericInst})
   case t.kind
   of tySequence, tyArray, tyArrayConstr, tyOpenArray, tyVarargs:
+    t.destructor = analyzingDestructor
     if instantiateDestructor(c, t.sons[0]) != nil:
       t.destructor = getCompilerProc"nimDestroyRange"
       return t
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 57fb3ceed..9f0696252 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -32,8 +32,7 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     # XXX tyGenericInst here?
     if result.typ.kind == tyVar: result = newDeref(result)
   elif {efWantStmt, efAllowStmt} * flags != {}:
-    result.typ = newTypeS(tyEmpty, c)
-    result.typ.flags.incl tfVoid
+    result.typ = newTypeS(tyVoid, c)
   else:
     localError(n.info, errExprXHasNoType,
                renderTree(result, {renderNoComments}))
@@ -51,7 +50,6 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
                renderTree(result, {renderNoComments}))
     result.typ = errorType(c)
   else:
-    # XXX tyGenericInst here?
     if efNoProcvarCheck notin flags: semProcvarCheck(c, result)
     if result.typ.kind == tyVar: result = newDeref(result)
     semDestructorCheck(c, result, flags)
@@ -199,6 +197,8 @@ proc semConv(c: PContext, n: PNode): PNode =
       # separate proc from fitNode?
       if op.kind == nkSym and op.sym.isGenericRoutine:
         result.sons[1] = fitNode(c, result.typ, result.sons[1])
+      elif op.kind == nkPar and targetType.kind == tyTuple:
+        op = fitNode(c, targetType, op)
     of convNotNeedeed:
       message(n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString)
     of convNotLegal:
@@ -601,6 +601,9 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
   result = n
   if n.kind notin nkCallKinds or n.sons[0].kind != nkSym: return
   var callee = n.sons[0].sym
+  # workaround for bug #537 (overly aggressive inlining leading to
+  # wrong NimNode semantics):
+  if n.typ != nil and tfTriggersCompileTime in n.typ.flags: return
 
   # constant folding that is necessary for correctness of semantic pass:
   if callee.magic != mNone and callee.magic in ctfeWhitelist and n.typ != nil:
@@ -1063,8 +1066,11 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
     result = newSymNode(s, n.info)
     result.typ = makeTypeDesc(c, s.typ)
   of skField:
-    if c.p != nil and c.p.selfSym != nil:
-      var ty = skipTypes(c.p.selfSym.typ, {tyGenericInst, tyVar, tyPtr, tyRef})
+    var p = c.p
+    while p != nil and p.selfSym == nil:
+      p = p.next
+    if p != nil and p.selfSym != nil:
+      var ty = skipTypes(p.selfSym.typ, {tyGenericInst, tyVar, tyPtr, tyRef})
       while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct})
       var check: PNode = nil
       if ty.kind == tyObject:
@@ -1077,7 +1083,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
             markUsed(n.info, f)
             styleCheckUse(n.info, f)
             result = newNodeIT(nkDotExpr, n.info, f.typ)
-            result.add makeDeref(newSymNode(c.p.selfSym))
+            result.add makeDeref(newSymNode(p.selfSym))
             result.add newSymNode(f) # we now have the correct field
             if check != nil:
               check.sons[0] = result
@@ -1385,15 +1391,16 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
     # --> `[]=`(a, i, x)
     let oldBracketExpr = c.p.bracketExpr
     a = semSubscript(c, a, {efLValue})
-    if a == nil and mode != noOverloadedSubscript:
+    if a == nil:
       result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=")
       add(result, n[1])
-      result = semExprNoType(c, result)
-      c.p.bracketExpr = oldBracketExpr
-      return result
-    elif a == nil:
-      localError(n.info, "could not resolve: " & $n[0])
-      return n
+      if mode == noOverloadedSubscript:
+        bracketNotFoundError(c, result)
+        return n
+      else:
+        result = semExprNoType(c, result)
+        c.p.bracketExpr = oldBracketExpr
+        return result
     c.p.bracketExpr = oldBracketExpr
   of nkCurlyExpr:
     # a{i} = x -->  `{}=`(a, i, x)
@@ -1629,8 +1636,8 @@ proc newAnonSym(kind: TSymKind, info: TLineInfo,
   result.flags = {sfGenSym}
 
 proc semExpandToAst(c: PContext, n: PNode): PNode =
-  var macroCall = n[1]
-  var expandedSym = expectMacroOrTemplateCall(c, macroCall)
+  let macroCall = n[1]
+  let expandedSym = expectMacroOrTemplateCall(c, macroCall)
   if expandedSym.kind == skError: return n
 
   macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
@@ -1638,11 +1645,12 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
   styleCheckUse(n.info, expandedSym)
 
   for i in countup(1, macroCall.len-1):
+    #if macroCall.sons[0].typ.sons[i].kind != tyExpr:
     macroCall.sons[i] = semExprWithType(c, macroCall[i], {})
 
   # Preserve the magic symbol in order to be handled in evals.nim
   internalAssert n.sons[0].sym.magic == mExpandToAst
-  #n.typ = getSysSym("PNimrodNode").typ # expandedSym.getReturnType
+  #n.typ = getSysSym("NimNode").typ # expandedSym.getReturnType
   n.typ = if getCompilerProc("NimNode") != nil: sysTypeFromName"NimNode"
           else: sysTypeFromName"PNimrodNode"
   result = n
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index feea6ce34..e9ee50d74 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -286,13 +286,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
   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 mLengthStr, mXLenStr:
-    if a.kind == nkNilLit: result = newIntNodeT(0, n)
-    else: result = newIntNodeT(len(getStr(a)), n)
   of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n)
-  of mLengthSeq, mLengthOpenArray, mXLenSeq:
-    if a.kind == nkNilLit: result = newIntNodeT(0, n)
-    else: result = newIntNodeT(sonsLen(a), n) # BUGFIX
+  of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr:
+    if a.kind == nkNilLit:
+      result = newIntNodeT(0, n)
+    elif a.kind in {nkStrLit..nkTripleStrLit}:
+      result = newIntNodeT(len a.strVal, n)
+    else:
+      result = newIntNodeT(sonsLen(a), n) # BUGFIX
   of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
   of mToFloat, mToBiggestFloat:
     result = newFloatNodeT(toFloat(int(getInt(a))), n)
@@ -634,12 +635,18 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
       of mCompileDate: result = newStrNodeT(times.getDateStr(), n)
       of mCompileTime: result = newStrNodeT(times.getClockStr(), n)
       of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n)
-      of mHostOS: result = newStrNodeT(toLower(platform.OS[targetOS].name), n)
-      of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLower, n)
+      of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n)
+      of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].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)
+      of mIntDefine:
+        if isDefined(s.name):
+          result = newIntNodeT(lookupSymbol(s.name).parseInt, n)
+      of mStrDefine:
+        if isDefined(s.name):
+          result = newStrNodeT(lookupSymbol(s.name), n)
       else:
         if sfFakeConst notin s.flags: result = copyTree(s.ast)
     of {skProc, skMethod}:
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index 0ba76ccd3..b78679411 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -426,7 +426,12 @@ proc semGenericStmt(c: PContext, n: PNode,
       n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx)
     n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, ctx)
     var body: PNode
-    if n.sons[namePos].kind == nkSym: body = n.sons[namePos].sym.getBody
+    if n.sons[namePos].kind == nkSym:
+      let s = n.sons[namePos].sym
+      if sfGenSym in s.flags and s.ast == nil:
+        body = n.sons[bodyPos]
+      else:
+        body = s.getBody
     else: body = n.sons[bodyPos]
     n.sons[bodyPos] = semGenericStmtScope(c, body, flags, ctx)
     closeScope(c)
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index e4ac56cd6..460db4f7c 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -205,7 +205,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
   # The solution would be to move this logic into semtypinst, but
   # at this point semtypinst have to become part of sem, because it
   # will need to use openScope, addDecl, etc.
-  addDecl(c, prc)
+  #addDecl(c, prc)
 
   pushInfoContext(info)
   var cl = initTypeVars(c, pt, info, nil)
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 1945d87eb..451745884 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -42,7 +42,10 @@ proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
   result = semSubscript(c, result, flags)
   c.p.bracketExpr = oldBracketExpr
   if result.isNil:
-    localError(n.info, "could not resolve: " & $n)
+    let x = copyTree(n)
+    x.sons[0] = newIdentNode(getIdent"[]", n.info)
+    bracketNotFoundError(c, x)
+    #localError(n.info, "could not resolve: " & $n)
     result = n
 
 proc semArrPut(c: PContext; n: PNode; flags: TExprFlags): PNode =
diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim
index b04ba4657..a4ec14250 100644
--- a/compiler/semparallel.nim
+++ b/compiler/semparallel.nim
@@ -74,8 +74,6 @@ type
     currentSpawnId: int
     inLoop: int
 
-let opSlice = createMagic("slice", mSlice)
-
 proc initAnalysisCtx(): AnalysisCtx =
   result.locals = @[]
   result.slices = @[]
@@ -399,7 +397,9 @@ proc transformSlices(n: PNode): PNode =
     let op = n[0].sym
     if op.name.s == "[]" and op.fromSystem:
       result = copyNode(n)
-      result.add opSlice.newSymNode
+      let opSlice = newSymNode(createMagic("slice", mSlice))
+      opSlice.typ = getSysType(tyInt)
+      result.add opSlice
       result.add n[1]
       let slice = n[2].skipStmtList
       result.add slice[1]
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 7155f9c7a..1f076aa31 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -138,7 +138,7 @@ proc fixNilType(n: PNode) =
 
 proc discardCheck(c: PContext, result: PNode) =
   if c.inTypeClass > 0: return
-  if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}:
+  if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
     if result.kind == nkNilLit:
       result.typ = nil
       message(result.info, warnNilStatement)
@@ -411,6 +411,13 @@ proc semUsing(c: PContext; n: PNode): PNode =
     if a.sons[length-1].kind != nkEmpty:
       localError(a.info, "'using' sections cannot contain assignments")
 
+proc hasEmpty(typ: PType): bool =
+  if typ.kind in {tySequence, tyArray, tySet}:
+    result = typ.lastSon.kind == tyEmpty
+  elif typ.kind == tyTuple:
+    for s in typ.sons:
+      result = result or hasEmpty(s)
+
 proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
   var b: PNode
   result = copyNode(n)
@@ -445,10 +452,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
           #changeType(def.skipConv, typ, check=true)
       else:
         typ = skipIntLit(def.typ)
-        if typ.kind in {tySequence, tyArray, tySet} and
-           typ.lastSon.kind == tyEmpty:
+        if hasEmpty(typ):
           localError(def.info, errCannotInferTypeOfTheLiteral,
-                     ($typ.kind).substr(2).toLower)
+                     ($typ.kind).substr(2).toLowerAscii)
     else:
       def = ast.emptyNode
       if symkind == skLet: localError(a.info, errLetNeedsInit)
@@ -711,7 +717,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
       a.sons[1] = s.typ.n
       s.typ.size = -1 # could not be computed properly
       # we fill it out later. For magic generics like 'seq', it won't be filled
-      # so we use tyEmpty instead of nil to not crash for strange conversions
+      # so we use tyNone instead of nil to not crash for strange conversions
       # like: mydata.seq
       rawAddSon(s.typ, newTypeS(tyNone, c))
       s.ast = a
@@ -1246,6 +1252,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     pushOwner(s)
   s.options = gOptions
   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 not experimentalMode(c):
+      message(n.info, warnDeprecated, "overloaded '.' and '()' operators are now .experimental; " & s.name.s)
   if n.sons[bodyPos].kind != nkEmpty:
     # for DLL generation it is annoying to check for sfImportc!
     if sfBorrow in s.flags:
@@ -1343,7 +1352,19 @@ proc semMethod(c: PContext, n: PNode): PNode =
   # macros can transform methods to nothing:
   if namePos >= result.safeLen: return result
   var s = result.sons[namePos].sym
-  if not isGenericRoutine(s):
+  if isGenericRoutine(s):
+    let tt = s.typ
+    var foundObj = false
+    for col in countup(0, sonsLen(tt)-1):
+      let t = tt.sons[col]
+      if t != nil and t.kind == tyGenericInvocation:
+        var x = skipTypes(t.sons[0], {tyVar, tyPtr, tyRef, tyGenericInst, tyGenericInvocation, tyGenericBody})
+        if x.kind == tyObject:
+          foundObj = true
+          x.methods.safeAdd((col,s))
+    if not foundObj:
+      message(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.
     # and result.sons[bodyPos].kind != nkEmpty:
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 13b283fe5..26ce28852 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -130,7 +130,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
   if n.len < 1:
     result = newConstraint(c, kind)
   else:
-    let isCall = ord(n.kind in nkCallKinds)
+    let isCall = ord(n.kind in nkCallKinds+{nkBracketExpr})
     let n = if n[0].kind == nkBracket: n[0] else: n
     checkMinSonsLen(n, 1)
     var base = semTypeNode(c, n.lastSon, nil)
@@ -370,7 +370,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
   result.n = newNodeI(nkRecList, n.info)
   var check = initIntSet()
   var counter = 0
-  for i in countup(0, sonsLen(n) - 1):
+  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)
@@ -945,7 +945,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       if isType: localError(a.info, "':' expected")
       if kind in {skTemplate, skMacro}:
         typ = newTypeS(tyExpr, c)
-    elif skipTypes(typ, {tyGenericInst}).kind == tyEmpty:
+    elif skipTypes(typ, {tyGenericInst}).kind == tyVoid:
       continue
     for j in countup(0, length-3):
       var arg = newSymG(skParam, a.sons[j], c)
@@ -977,7 +977,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
   if r != nil:
     # turn explicit 'void' return type into 'nil' because the rest of the
     # compiler only checks for 'nil':
-    if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
+    if skipTypes(r, {tyGenericInst}).kind != tyVoid:
       # 'auto' as a return type does not imply a generic:
       if r.kind == tyAnything:
         # 'p(): auto' and 'p(): expr' are equivalent, but the rest of the
@@ -1038,7 +1038,7 @@ proc semGenericParamInInvocation(c: PContext, n: PNode): PType =
 proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
   if s.typ == nil:
     localError(n.info, "cannot instantiate the '$1' $2" %
-                       [s.name.s, ($s.kind).substr(2).toLower])
+                       [s.name.s, ($s.kind).substr(2).toLowerAscii])
     return newOrPrevType(tyError, prev, c)
 
   var t = s.typ
@@ -1248,6 +1248,19 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
         result = copyType(result, getCurrOwner(), false)
         for i in countup(1, n.len - 1):
           result.rawAddSon(semTypeNode(c, n.sons[i], nil))
+    of mDistinct:
+      result = newOrPrevType(tyDistinct, prev, c)
+      addSonSkipIntLit(result, semTypeNode(c, n[1], nil))
+    of mVar:
+      result = newOrPrevType(tyVar, prev, c)
+      var base = semTypeNode(c, n.sons[1], nil)
+      if base.kind == tyVar:
+        localError(n.info, errVarVarTypeNotAllowed)
+        base = base.sons[0]
+      addSonSkipIntLit(result, base)
+    of mRef: result = semAnyRef(c, n, tyRef, prev)
+    of mPtr: result = semAnyRef(c, n, tyPtr, prev)
+    of mTuple: result = semTuple(c, n, prev)
     else: result = semGeneric(c, n, s, prev)
   of nkDotExpr:
     var typeExpr = semExpr(c, n)
@@ -1377,10 +1390,7 @@ proc processMagicType(c: PContext, m: PSym) =
     setMagicType(m, tyTypeDesc, 0)
     rawAddSon(m.typ, newTypeS(tyNone, c))
   of mVoidType:
-    setMagicType(m, tyEmpty, 0)
-    # for historical reasons we conflate 'void' with 'empty' so that '@[]'
-    # has the type 'seq[void]'.
-    m.typ.flags.incl tfVoid
+    setMagicType(m, tyVoid, 0)
   of mArray:
     setMagicType(m, tyArray, 0)
   of mOpenArray:
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 7ff33f918..076679bbf 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -162,7 +162,7 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
     discard
   of nkSym:
     result.sym = replaceTypeVarsS(cl, n.sym)
-    if result.sym.typ.kind == tyEmpty:
+    if result.sym.typ.kind == tyVoid:
       # don't add the 'void' field
       result = newNode(nkRecList, n.info)
   of nkRecWhen:
@@ -289,7 +289,8 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
     # but we already raised an error!
     rawAddSon(result, header.sons[i])
 
-  var newbody = replaceTypeVarsT(cl, lastSon(body))
+  let bbody = lastSon body
+  var newbody = replaceTypeVarsT(cl, bbody)
   cl.skipTypedesc = oldSkipTypedesc
   newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
   result.flags = result.flags + newbody.flags - tfInstClearedFlags
@@ -306,25 +307,31 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
     # 'deepCopy' needs to be instantiated for
     # generics *when the type is constructed*:
     newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
-                                            attachedDeepCopy)
+                                            attachedDeepCopy, 1)
   let asgn = newbody.assignment
   if asgn != nil and sfFromGeneric notin asgn.flags:
     # '=' needs to be instantiated for generics when the type is constructed:
     newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info,
-                                              attachedAsgn)
+                                              attachedAsgn, 1)
+  let methods = skipTypes(bbody, abstractPtrs).methods
+  for col, meth in items(methods):
+    # we instantiate the known methods belonging to that type, this causes
+    # them to be registered and that's enough, so we 'discard' the result.
+    discard cl.c.instTypeBoundOp(cl.c, meth, result, cl.info,
+      attachedAsgn, col)
 
 proc eraseVoidParams*(t: PType) =
   # transform '(): void' into '()' because old parts of the compiler really
   # don't deal with '(): void':
-  if t.sons[0] != nil and t.sons[0].kind == tyEmpty:
+  if t.sons[0] != nil and t.sons[0].kind == tyVoid:
     t.sons[0] = nil
 
   for i in 1 .. <t.sonsLen:
     # don't touch any memory unless necessary
-    if t.sons[i].kind == tyEmpty:
+    if t.sons[i].kind == tyVoid:
       var pos = i
       for j in i+1 .. <t.sonsLen:
-        if t.sons[j].kind != tyEmpty:
+        if t.sons[j].kind != tyVoid:
           t.sons[pos] = t.sons[j]
           t.n.sons[pos] = t.n.sons[j]
           inc pos
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index df27e3c1d..9a8f865a6 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -22,7 +22,7 @@ type
   TCandidateState* = enum
     csEmpty, csMatch, csNoMatch
 
-  CandidateErrors* = seq[PSym]
+  CandidateErrors* = seq[(PSym,int)]
   TCandidate* = object
     c*: PContext
     exactMatches*: int       # also misused to prefer iters over procs
@@ -49,6 +49,7 @@ type
                              # a distrinct type
     typedescMatched*: bool
     isNoCall*: bool          # misused for generic type instantiations C[T]
+    mutabilityProblem*: uint8 # tyVar mismatch
     inheritancePenalty: int  # to prefer closest father object type
     errors*: CandidateErrors # additional clarifications to be displayed to the
                              # user if overload resolution fails
@@ -363,6 +364,46 @@ proc isObjectSubtype(a, f: PType): int =
   if t != nil:
     result = depth
 
+type
+  SkippedPtr = enum skippedNone, skippedRef, skippedPtr
+
+proc skipToGenericBody(t: PType; skipped: var SkippedPtr): PType =
+  var r = t
+  # we're allowed to skip one level of ptr/ref:
+  var ptrs = 0
+  while r != nil:
+    case r.kind
+    of tyGenericInst, tyGenericInvocation:
+      result = r.sons[0]
+      break
+    of tyRef:
+      inc ptrs
+      skipped = skippedRef
+      r = r.lastSon
+    of tyPtr:
+      inc ptrs
+      skipped = skippedPtr
+      r = r.lastSon
+    of tyGenericBody, tyObject:
+      r = r.lastSon
+    else:
+      break
+  if ptrs > 1: result = nil
+
+proc isGenericSubtype(a, f: PType, d: var int): bool =
+  assert f.kind in {tyGenericInst, tyGenericInvocation, tyGenericBody}
+  var askip = skippedNone
+  var fskip = skippedNone
+  var t = if a.kind == tyGenericBody: a else: a.skipToGenericBody(askip)
+  var r = if f.kind == tyGenericBody: f else: f.skipToGenericBody(fskip)
+  var depth = 0
+  while t != nil and not sameObjectTypes(r, t) and askip == fskip:
+    t = t.skipToGenericBody(askip)
+    inc depth
+  if t != nil and askip == fskip:
+    d = depth
+    result = true
+
 proc minRel(a, b: TTypeRelation): TTypeRelation =
   if a <= b: result = a
   else: result = b
@@ -647,7 +688,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   template bindingRet(res) =
     if doBind:
       let bound = aOrig.skipTypes({tyRange}).skipIntLit
-      if doBind: put(c.bindings, f, bound)
+      put(c.bindings, f, bound)
     return res
 
   template considerPreviousT(body: stmt) {.immediate.} =
@@ -930,8 +971,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
         result = isConvertible
     else: discard
 
-  of tyEmpty:
-    if a.kind == tyEmpty: result = isEqual
+  of tyEmpty, tyVoid:
+    if a.kind == f.kind: result = isEqual
 
   of tyGenericInst:
     result = typeRel(c, lastSon(f), a)
@@ -945,17 +986,19 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
 
   of tyGenericInvocation:
     var x = a.skipGenericAlias
+    var depth = 0
     if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody:
       #InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
       # simply no match for now:
       discard
     elif x.kind == tyGenericInst and
-          (f.sons[0] == x.sons[0]) and
+          ((f.sons[0] == x.sons[0]) or isGenericSubtype(x, f, depth)) and
           (sonsLen(x) - 1 == sonsLen(f)):
       for i in countup(1, sonsLen(f) - 1):
         if x.sons[i].kind == tyGenericParam:
           internalError("wrong instantiated type!")
         elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return
+      c.inheritancePenalty += depth
       result = isGeneric
     else:
       let genericBody = f.sons[0]
@@ -1408,7 +1451,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
     if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
       result = implicitConv(nkHiddenSubConv, f, arg, m, c)
   of isNone:
-    # do not do this in ``typeRel`` as it then can't infere T in ``ref T``:
+    # do not do this in ``typeRel`` as it then can't infer T in ``ref T``:
     if a.kind in {tyProxy, tyUnknown}:
       inc(m.genericMatches)
       m.fauxMatch = a.kind
@@ -1429,6 +1472,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
           m.baseTypeMatch = true
         else:
           result = userConvMatch(c, m, base(f), a, arg)
+          if result != nil: m.baseTypeMatch = true
 
 proc paramTypesMatch*(m: var TCandidate, f, a: PType,
                       arg, argOrig: PNode): PNode =
@@ -1558,6 +1602,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
     if formal.typ.kind == tyVar:
       if not n.isLValue:
         m.state = csNoMatch
+        m.mutabilityProblem = uint8(f-1)
         return
 
   var
@@ -1577,6 +1622,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
 
   while a < n.len:
     if a >= formalLen-1 and formal != nil and formal.typ.isVarargsUntyped:
+      incl(marker, formal.position)
       if container.isNil:
         container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, n.info))
         setSon(m.call, formal.position + 1, container)
@@ -1639,6 +1685,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           # beware of the side-effects in 'prepareOperand'! So only do it for
           # varargs matching. See tests/metatype/tstatic_overloading.
           m.baseTypeMatch = false
+          incl(marker, formal.position)
           n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
           var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
                                     n.sons[a], nOrig.sons[a])
@@ -1725,15 +1772,18 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
       if formal.ast == nil:
         if formal.typ.kind == tyVarargs:
           var container = newNodeIT(nkBracket, n.info, arrayConstr(c, n.info))
-          addSon(m.call, implicitConv(nkHiddenStdConv, formal.typ,
-                                      container, m, c))
+          setSon(m.call, formal.position + 1,
+                 implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
         else:
           # no default value
           m.state = csNoMatch
           break
       else:
         # use default value:
-        setSon(m.call, formal.position + 1, copyTree(formal.ast))
+        var def = copyTree(formal.ast)
+        if def.kind == nkNilLit:
+          def = implicitConv(nkHiddenStdConv, formal.typ, def, m, c)
+        setSon(m.call, formal.position + 1, def)
     inc(f)
 
 proc argtypeMatches*(c: PContext, f, a: PType): bool =
@@ -1746,16 +1796,19 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool =
   result = res != nil
 
 proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
-                      op: TTypeAttachedOp): PSym {.procvar.} =
+                      op: TTypeAttachedOp; col: int): PSym {.procvar.} =
   var m: TCandidate
   initCandidate(c, m, dc.typ)
-  var f = dc.typ.sons[1]
+  if col >= dc.typ.len:
+    localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
+    return nil
+  var f = dc.typ.sons[col]
   if op == attachedDeepCopy:
     if f.kind in {tyRef, tyPtr}: f = f.lastSon
   else:
     if f.kind == tyVar: f = f.lastSon
   if typeRel(m, f, t) == isNone:
-    localError(info, errGenerated, "cannot instantiate 'deepCopy'")
+    localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
   else:
     result = c.semGenerateInstance(c, dc, m.bindings, info)
     assert sfFromGeneric in result.flags
diff --git a/compiler/types.nim b/compiler/types.nim
index bada47075..5fbab85b9 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -407,7 +407,8 @@ const
     "!", "varargs[$1]", "iter[$1]", "Error Type",
     "BuiltInTypeClass", "UserTypeClass",
     "UserTypeClassInst", "CompositeTypeClass",
-    "and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor"]
+    "and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor",
+    "void"]
 
 const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg}
 
@@ -540,7 +541,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
     else:
       result.add typeToString(t.sons[0])
   of tyRange:
-    result = "range " & rangeToStr(t.n)
+    result = "range "
+    if t.n != nil and t.n.kind == nkRange:
+      result.add rangeToStr(t.n)
     if prefer != preferExported:
       result.add("(" & typeToString(t.sons[0]) & ")")
   of tyProc:
@@ -727,6 +730,7 @@ proc equalParam(a, b: PSym): TParamsEquality =
     result = paramsNotEqual
 
 proc sameConstraints(a, b: PNode): bool =
+  if isNil(a) and isNil(b): return true
   internalAssert a.len == b.len
   for i in 1 .. <a.len:
     if not exprStructuralEquivalent(a[i].sym.constraint,
@@ -799,6 +803,8 @@ proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
           result = x.name.id == y.name.id
           if not result: break
         else: internalError(a.n.info, "sameTuple")
+    elif a.n != b.n and (a.n == nil or b.n == nil) and IgnoreTupleFields notin c.flags:
+      result = false
 
 template ifFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} =
   if tfFromGeneric notin a.flags + b.flags:
@@ -922,7 +928,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
 
   case a.kind
   of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
-     tyInt..tyBigNum, tyStmt, tyExpr:
+     tyInt..tyBigNum, tyStmt, tyExpr, tyVoid:
     result = sameFlags(a, b)
   of tyStatic, tyFromExpr:
     result = exprStructuralEquivalent(a.n, b.n) and sameFlags(a, b)
@@ -1108,7 +1114,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
     result = nil
   of tyExpr, tyStmt, tyStatic:
     if kind notin {skParam, skResult}: result = t
-  of tyEmpty:
+  of tyVoid:
     if taField notin flags: result = t
   of tyTypeClasses:
     if not (tfGenericTypeParam in t.flags or taField notin flags): result = t
@@ -1153,7 +1159,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
       if result != nil: break
     if result.isNil and t.n != nil:
       result = typeAllowedNode(marker, t.n, kind, flags)
-  of tyProxy:
+  of tyProxy, tyEmpty:
     # for now same as error node; we say it's a valid type as it should
     # prevent cascading errors:
     result = nil
@@ -1313,6 +1319,9 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
   of tyTypeDesc:
     result = computeSizeAux(typ.base, a)
   of tyForward: return szIllegalRecursion
+  of tyStatic:
+    if typ.n != nil: result = computeSizeAux(lastSon(typ), a)
+    else: result = szUnknownSize
   else:
     #internalError("computeSizeAux()")
     result = szUnknownSize
diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim
index 678a765f4..a10e7c12e 100644
--- a/compiler/vmdeps.nim
+++ b/compiler/vmdeps.nim
@@ -63,8 +63,9 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
     localError(info, errCannotOpenFile, file)
     result = ""
 
-proc atomicTypeX(name: string; t: PType; info: TLineInfo): PNode =
+proc atomicTypeX(name: string; m: TMagic; t: PType; info: TLineInfo): PNode =
   let sym = newSym(skType, getIdent(name), t.owner, info)
+  sym.magic = m
   sym.typ = t
   result = newSymNode(sym)
   result.typ = t
@@ -72,14 +73,14 @@ proc atomicTypeX(name: string; t: PType; info: TLineInfo): PNode =
 proc mapTypeToAstX(t: PType; info: TLineInfo;
                    inst=false; allowRecursionX=false): PNode
 
-proc mapTypeToBracketX(name: string; t: PType; info: TLineInfo;
+proc mapTypeToBracketX(name: string; m: TMagic; t: PType; info: TLineInfo;
                        inst=false): PNode =
   result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
-  result.add atomicTypeX(name, t, info)
+  result.add atomicTypeX(name, m, t, info)
   for i in 0 .. < t.len:
     if t.sons[i] == nil:
-      let void = atomicTypeX("void", t, info)
-      void.typ = newType(tyEmpty, t.owner)
+      let void = atomicTypeX("void", mVoid, t, info)
+      void.typ = newType(tyVoid, t.owner)
       result.add void
     else:
       result.add mapTypeToAstX(t.sons[i], info, inst)
@@ -87,14 +88,14 @@ proc mapTypeToBracketX(name: string; t: PType; info: TLineInfo;
 proc mapTypeToAstX(t: PType; info: TLineInfo;
                    inst=false; allowRecursionX=false): PNode =
   var allowRecursion = allowRecursionX
-  template atomicType(name): expr = atomicTypeX(name, t, info)
+  template atomicType(name, m): expr = atomicTypeX(name, m, t, info)
   template mapTypeToAst(t,info): expr = mapTypeToAstX(t, info, inst)
   template mapTypeToAstR(t,info): expr = mapTypeToAstX(t, info, inst, true)
   template mapTypeToAst(t,i,info): expr =
     if i<t.len and t.sons[i]!=nil: mapTypeToAstX(t.sons[i], info, inst)
     else: ast.emptyNode
-  template mapTypeToBracket(name,t,info): expr =
-    mapTypeToBracketX(name, t, info, inst)
+  template mapTypeToBracket(name, m, t, info): expr =
+    mapTypeToBracketX(name, m, t, info, inst)
   template newNodeX(kind):expr =
     newNodeIT(kind, if t.n.isNil: info else: t.n.info, t)
   template newIdent(s):expr =
@@ -114,19 +115,20 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
       if allowRecursion:  # getTypeImpl behavior: turn off recursion
         allowRecursion = false
       else:  # getTypeInst behavior: return symbol
-        return atomicType(t.sym.name.s)
+        return atomicType(t.sym.name.s, t.sym.magic)
 
   case t.kind
-  of tyNone: result = atomicType("none")
-  of tyBool: result = atomicType("bool")
-  of tyChar: result = atomicType("char")
-  of tyNil: result = atomicType("nil")
-  of tyExpr: result = atomicType("expr")
-  of tyStmt: result = atomicType("stmt")
-  of tyEmpty: result = atomicType"void"
+  of tyNone: result = atomicType("none", mNone)
+  of tyBool: result = atomicType("bool", mBool)
+  of tyChar: result = atomicType("char", mChar)
+  of tyNil: result = atomicType("nil", mNil)
+  of tyExpr: result = atomicType("expr", mExpr)
+  of tyStmt: result = atomicType("stmt", mStmt)
+  of tyVoid: result = atomicType("void", mVoid)
+  of tyEmpty: result = atomicType("empty", mNone)
   of tyArrayConstr, tyArray:
     result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
-    result.add atomicType("array")
+    result.add atomicType("array", mArray)
     if inst and t.sons[0].kind == tyRange:
       var rng = newNodeX(nkInfix)
       rng.add newIdentNode(getIdent(".."), info)
@@ -139,10 +141,10 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
   of tyTypeDesc:
     if t.base != nil:
       result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
-      result.add atomicType("typeDesc")
+      result.add atomicType("typeDesc", mTypeDesc)
       result.add mapTypeToAst(t.base, info)
     else:
-      result = atomicType"typeDesc"
+      result = atomicType("typeDesc", mTypeDesc)
   of tyGenericInvocation:
     result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
     for i in 0 .. < t.len:
@@ -166,10 +168,11 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
       result.add mapTypeToAst(t.sons[0], info)
     else:
       if allowRecursion or t.sym==nil:
-        result = mapTypeToBracket("distinct", t, info)
+        result = mapTypeToBracket("distinct", mDistinct, t, info)
       else:
-        result = atomicType(t.sym.name.s)
-  of tyGenericParam, tyForward: result = atomicType(t.sym.name.s)
+        result = atomicType(t.sym.name.s, t.sym.magic)
+  of tyGenericParam, tyForward:
+    result = atomicType(t.sym.name.s, t.sym.magic)
   of tyObject:
     if inst:
       result = newNodeX(nkObjectTy)
@@ -196,7 +199,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
           result.add mapTypeToAst(t.sons[0], info)
         result.add copyTree(t.n)
       else:
-        result = atomicType(t.sym.name.s)
+        result = atomicType(t.sym.name.s, t.sym.magic)
   of tyEnum:
     result = newNodeIT(nkEnumTy, if t.n.isNil: info else: t.n.info, t)
     result.add copyTree(t.n)
@@ -206,22 +209,22 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
       for s in t.n.sons:
         result.add newIdentDefs(s)
     else:
-      result = mapTypeToBracket("tuple", t, info)
-  of tySet: result = mapTypeToBracket("set", t, info)
+      result = mapTypeToBracket("tuple", mTuple, t, info)
+  of tySet: result = mapTypeToBracket("set", mSet, t, info)
   of tyPtr:
     if inst:
       result = newNodeX(nkPtrTy)
       result.add mapTypeToAst(t.sons[0], info)
     else:
-      result = mapTypeToBracket("ptr", t, info)
+      result = mapTypeToBracket("ptr", mPtr, t, info)
   of tyRef:
     if inst:
       result = newNodeX(nkRefTy)
       result.add mapTypeToAst(t.sons[0], info)
     else:
-      result = mapTypeToBracket("ref", t, info)
-  of tyVar: result = mapTypeToBracket("var", t, info)
-  of tySequence: result = mapTypeToBracket("seq", t, info)
+      result = mapTypeToBracket("ref", mRef, t, info)
+  of tyVar: result = mapTypeToBracket("var", mVar, t, info)
+  of tySequence: result = mapTypeToBracket("seq", mSeq, t, info)
   of tyProc:
     if inst:
       result = newNodeX(nkProcTy)
@@ -235,52 +238,54 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
       result.add fp
       result.add ast.emptyNode  # pragmas aren't reconstructed yet
     else:
-      result = mapTypeToBracket("proc", t, info)
-  of tyOpenArray: result = mapTypeToBracket("openArray", t, info)
+      result = mapTypeToBracket("proc", mNone, t, info)
+  of tyOpenArray: result = mapTypeToBracket("openArray", mOpenArray, t, info)
   of tyRange:
     result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
-    result.add atomicType("range")
+    result.add atomicType("range", mRange)
     result.add t.n.sons[0].copyTree
     result.add t.n.sons[1].copyTree
-  of tyPointer: result = atomicType"pointer"
-  of tyString: result = atomicType"string"
-  of tyCString: result = atomicType"cstring"
-  of tyInt: result = atomicType"int"
-  of tyInt8: result = atomicType"int8"
-  of tyInt16: result = atomicType"int16"
-  of tyInt32: result = atomicType"int32"
-  of tyInt64: result = atomicType"int64"
-  of tyFloat: result = atomicType"float"
-  of tyFloat32: result = atomicType"float32"
-  of tyFloat64: result = atomicType"float64"
-  of tyFloat128: result = atomicType"float128"
-  of tyUInt: result = atomicType"uint"
-  of tyUInt8: result = atomicType"uint8"
-  of tyUInt16: result = atomicType"uint16"
-  of tyUInt32: result = atomicType"uint32"
-  of tyUInt64: result = atomicType"uint64"
-  of tyBigNum: result = atomicType"bignum"
-  of tyConst: result = mapTypeToBracket("const", t, info)
-  of tyMutable: result = mapTypeToBracket("mutable", t, info)
-  of tyVarargs: result = mapTypeToBracket("varargs", t, info)
-  of tyIter: result = mapTypeToBracket("iter", t, info)
-  of tyProxy: result = atomicType"error"
-  of tyBuiltInTypeClass: result = mapTypeToBracket("builtinTypeClass", t, info)
+  of tyPointer: result = atomicType("pointer", mPointer)
+  of tyString: result = atomicType("string", mString)
+  of tyCString: result = atomicType("cstring", mCString)
+  of tyInt: result = atomicType("int", mInt)
+  of tyInt8: result = atomicType("int8", mInt8)
+  of tyInt16: result = atomicType("int16", mInt16)
+  of tyInt32: result = atomicType("int32", mInt32)
+  of tyInt64: result = atomicType("int64", mInt64)
+  of tyFloat: result = atomicType("float", mFloat)
+  of tyFloat32: result = atomicType("float32", mFloat32)
+  of tyFloat64: result = atomicType("float64", mFloat64)
+  of tyFloat128: result = atomicType("float128", mFloat128)
+  of tyUInt: result = atomicType("uint", mUint)
+  of tyUInt8: result = atomicType("uint8", mUint8)
+  of tyUInt16: result = atomicType("uint16", mUint16)
+  of tyUInt32: result = atomicType("uint32", mUint32)
+  of tyUInt64: result = atomicType("uint64", mUint64)
+  of tyBigNum: result = atomicType("bignum", mNone)
+  of tyConst: result = mapTypeToBracket("const", mNone, t, info)
+  of tyMutable: result = mapTypeToBracket("mutable", mNone, t, info)
+  of tyVarargs: result = mapTypeToBracket("varargs", mVarargs, t, info)
+  of tyIter: result = mapTypeToBracket("iter", mNone, t, info)
+  of tyProxy: result = atomicType("error", mNone)
+  of tyBuiltInTypeClass:
+    result = mapTypeToBracket("builtinTypeClass", mNone, t, info)
   of tyUserTypeClass:
-    result = mapTypeToBracket("concept", t, info)
+    result = mapTypeToBracket("concept", mNone, t, info)
     result.add t.n.copyTree
-  of tyCompositeTypeClass: result = mapTypeToBracket("compositeTypeClass", t, info)
-  of tyAnd: result = mapTypeToBracket("and", t, info)
-  of tyOr: result = mapTypeToBracket("or", t, info)
-  of tyNot: result = mapTypeToBracket("not", t, info)
-  of tyAnything: result = atomicType"anything"
+  of tyCompositeTypeClass:
+    result = mapTypeToBracket("compositeTypeClass", mNone, t, info)
+  of tyAnd: result = mapTypeToBracket("and", mAnd, t, info)
+  of tyOr: result = mapTypeToBracket("or", mOr, t, info)
+  of tyNot: result = mapTypeToBracket("not", mNot, t, info)
+  of tyAnything: result = atomicType("anything", mNone)
   of tyStatic, tyFromExpr, tyFieldAccessor:
     if inst:
       if t.n != nil: result = t.n.copyTree
-      else: result = atomicType "void"
+      else: result = atomicType("void", mVoid)
     else:
       result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
-      result.add atomicType "static"
+      result.add atomicType("static", mNone)
       if t.n != nil:
         result.add t.n.copyTree
 
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index d4966b3e3..1c1d03a4f 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -267,7 +267,7 @@ proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister =
 proc clearDest(c: PCtx; n: PNode; dest: var TDest) {.inline.} =
   # stmt is different from 'void' in meta programming contexts.
   # So we only set dest to -1 if 'void':
-  if dest >= 0 and (n.typ.isNil or n.typ.kind == tyEmpty):
+  if dest >= 0 and (n.typ.isNil or n.typ.kind == tyVoid):
     c.freeTemp(dest)
     dest = -1
 
@@ -374,7 +374,7 @@ proc canonValue*(n: PNode): PNode =
 
 proc rawGenLiteral(c: PCtx; n: PNode): int =
   result = c.constants.len
-  assert(n.kind != nkCall)
+  #assert(n.kind != nkCall)
   n.flags.incl nfAllConst
   c.constants.add n.canonValue
   internalAssert result < 0x7fff
@@ -497,12 +497,30 @@ proc genReturn(c: PCtx; n: PNode) =
     gen(c, n.sons[0])
   c.gABC(n, opcRet)
 
+
+proc genLit(c: PCtx; n: PNode; dest: var TDest) =
+  # opcLdConst is now always valid. We produce the necessary copy in the
+  # assignments now:
+  #var opc = opcLdConst
+  if dest < 0: dest = c.getTemp(n.typ)
+  #elif c.prc.slots[dest].kind == slotFixedVar: opc = opcAsgnConst
+  let lit = genLiteral(c, n)
+  c.gABx(n, opcLdConst, dest, lit)
+
 proc genCall(c: PCtx; n: PNode; dest: var TDest) =
+  # it can happen that due to inlining we have a 'n' that should be
+  # treated as a constant (see issue #537).
+  #if n.typ != nil and n.typ.sym != nil and n.typ.sym.magic == mPNimrodNode:
+  #  genLit(c, n, dest)
+  #  return
   if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
   let x = c.getTempRange(n.len, slotTempUnknown)
   # varargs need 'opcSetType' for the FFI support:
-  let fntyp = n.sons[0].typ
+  let fntyp = skipTypes(n.sons[0].typ, abstractInst)
   for i in 0.. <n.len:
+    #if i > 0 and i < sonsLen(fntyp):
+    #  let paramType = fntyp.n.sons[i]
+    #  if paramType.typ.isCompileTimeOnly: continue
     var r: TRegister = x+i
     c.gen(n.sons[i], r)
     if i >= fntyp.len:
@@ -579,16 +597,27 @@ proc genNew(c: PCtx; n: PNode) =
   c.freeTemp(dest)
 
 proc genNewSeq(c: PCtx; n: PNode) =
-  let dest = if needsAsgnPatch(n.sons[1]): c.getTemp(n.sons[1].typ)
+  let t = n.sons[1].typ
+  let dest = if needsAsgnPatch(n.sons[1]): c.getTemp(t)
              else: c.genx(n.sons[1])
   let tmp = c.genx(n.sons[2])
-  c.gABx(n, opcNewSeq, dest, c.genType(n.sons[1].typ.skipTypes(
+  c.gABx(n, opcNewSeq, dest, c.genType(t.skipTypes(
                                                   abstractVar-{tyTypeDesc})))
   c.gABx(n, opcNewSeq, tmp, 0)
   c.freeTemp(tmp)
   c.genAsgnPatch(n.sons[1], dest)
   c.freeTemp(dest)
 
+proc genNewSeqOfCap(c: PCtx; n: PNode; dest: var TDest) =
+  let t = n.typ
+  let tmp = c.getTemp(n.sons[1].typ)
+  c.gABx(n, opcLdNull, dest, c.genType(t))
+  c.gABx(n, opcLdImmInt, tmp, 0)
+  c.gABx(n, opcNewSeq, dest, c.genType(t.skipTypes(
+                                                  abstractVar-{tyTypeDesc})))
+  c.gABx(n, opcNewSeq, tmp, 0)
+  c.freeTemp(tmp)
+
 proc genUnaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
   let tmp = c.genx(n.sons[1])
   if dest < 0: dest = c.getTemp(n.typ)
@@ -764,6 +793,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mNewSeq:
     unused(n, dest)
     c.genNewSeq(n)
+  of mNewSeqOfCap: c.genNewSeqOfCap(n, dest)
   of mNewString:
     genUnaryABC(c, n, dest, opcNewStr)
     # XXX buggy
@@ -1307,15 +1337,6 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
     let dest = c.genx(le, {gfAddrOf})
     genAsgn(c, dest, ri, requiresCopy)
 
-proc genLit(c: PCtx; n: PNode; dest: var TDest) =
-  # opcLdConst is now always valid. We produce the necessary copy in the
-  # assignments now:
-  #var opc = opcLdConst
-  if dest < 0: dest = c.getTemp(n.typ)
-  #elif c.prc.slots[dest].kind == slotFixedVar: opc = opcAsgnConst
-  let lit = genLiteral(c, n)
-  c.gABx(n, opcLdConst, dest, lit)
-
 proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
   var n = newNode(nkType)
   n.typ = t
@@ -1677,10 +1698,10 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     of skType:
       genTypeLit(c, s.typ, dest)
     of skGenericParam:
-      if c.prc.sym.kind == skMacro:
+      if c.prc.sym != nil and c.prc.sym.kind == skMacro:
         genRdVar(c, n, dest, flags)
       else:
-        internalError(n.info, "cannot generate code for: " & s.name.s)
+        globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
     else:
       globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
   of nkCallKinds:
@@ -1788,6 +1809,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
       genConv(c, n, n.sons[1], dest, opcCast)
     else:
       globalError(n.info, errGenerated, "VM is not allowed to 'cast'")
+  of nkTypeOfExpr:
+    genTypeLit(c, n.typ, dest)
   else:
     globalError(n.info, errGenerated, "cannot generate VM code for " & $n)
 
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index 3e0e05a94..b5ffd51c2 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -36,6 +36,7 @@ type
     wColon, wColonColon, wEquals, wDot, wDotDot,
     wStar, wMinus,
     wMagic, wThread, wFinal, wProfiler, wObjChecks,
+    wIntDefine, wStrDefine,
 
     wDestroy,
 
@@ -121,7 +122,7 @@ const
 
     ":", "::", "=", ".", "..",
     "*", "-",
-    "magic", "thread", "final", "profiler", "objchecks",
+    "magic", "thread", "final", "profiler", "objchecks", "intdefine", "strdefine",
 
     "destroy",