summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim2
-rw-r--r--compiler/ccgexprs.nim126
-rw-r--r--compiler/ccgstmts.nim6
-rw-r--r--compiler/ccgtrav.nim16
-rw-r--r--compiler/ccgtypes.nim43
-rw-r--r--compiler/cgen.nim19
-rw-r--r--compiler/commands.nim9
-rw-r--r--compiler/condsyms.nim5
-rw-r--r--compiler/docgen.nim14
-rw-r--r--compiler/evalffi.nim16
-rw-r--r--compiler/extccomp.nim15
-rw-r--r--compiler/installer.ini5
-rw-r--r--compiler/jsgen.nim2
-rw-r--r--compiler/lambdalifting.nim2
-rw-r--r--compiler/lowerings.nim20
-rw-r--r--compiler/msgs.nim2
-rw-r--r--compiler/nimblecmd.nim112
-rw-r--r--compiler/nimconf.nim2
-rw-r--r--compiler/options.nim6
-rw-r--r--compiler/parser.nim13
-rw-r--r--compiler/passes.nim6
-rw-r--r--compiler/platform.nim15
-rw-r--r--compiler/pragmas.nim9
-rw-r--r--compiler/renderer.nim2
-rw-r--r--compiler/reorder.nim102
-rw-r--r--compiler/ropes.nim1
-rw-r--r--compiler/semexprs.nim65
-rw-r--r--compiler/semmagic.nim36
-rw-r--r--compiler/semobjconstr.nim7
-rw-r--r--compiler/semtempl.nim4
-rw-r--r--compiler/semtypes.nim36
-rw-r--r--compiler/sigmatch.nim4
-rw-r--r--compiler/testability.nim5
-rw-r--r--compiler/vm.nim62
-rw-r--r--compiler/vmdef.nim5
-rw-r--r--compiler/vmdeps.nim3
-rw-r--r--compiler/vmgen.nim36
-rw-r--r--compiler/wordrecg.nim4
38 files changed, 596 insertions, 241 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index ac917346f..0cc4daf22 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -292,6 +292,8 @@ const
 
   sfNoForward* = sfRegister
     # forward declarations are not required (per module)
+  sfReorder* = sfForward
+    # reordering pass is enabled
 
   sfCompileToCpp* = sfInfixCall       # compile the module as C++ code
   sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 0ec16710f..f5c793d29 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -744,14 +744,17 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
   addf(r, ".Field$1", [rope(i)])
   putIntoDest(p, d, tupType.sons[i], r, a.s)
 
-proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope): PSym =
+proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope;
+                      resTyp: ptr PType = nil): PSym =
   var ty = ty
   assert r != nil
   while ty != nil:
     ty = ty.skipTypes(skipPtrs)
     assert(ty.kind in {tyTuple, tyObject})
     result = lookupInRecord(ty.n, field.name)
-    if result != nil: break
+    if result != nil:
+      if resTyp != nil: resTyp[] = ty
+      break
     if not p.module.compileToCpp: add(r, ".Sup")
     ty = ty.sons[0]
   if result == nil: internalError(field.info, "genCheckedRecordField")
@@ -768,8 +771,9 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
     addf(r, ".Field$1", [rope(f.position)])
     putIntoDest(p, d, f.typ, r, a.s)
   else:
-    let field = lookupFieldAgain(p, ty, f, r)
-    if field.loc.r == nil: fillObjectFields(p.module, ty)
+    var rtyp: PType
+    let field = lookupFieldAgain(p, ty, f, r, addr rtyp)
+    if field.loc.r == nil and rtyp != nil: fillObjectFields(p.module, rtyp)
     if field.loc.r == nil: internalError(e.info, "genRecordField 3 " & typeToString(ty))
     addf(r, ".$1", [field.loc.r])
     putIntoDest(p, d, field.typ, r, a.s)
@@ -1057,7 +1061,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
                            "$1 = ($2) #incrSeqV2(&($1)->Sup, sizeof($3));$n"
                          else:
                            "$1 = ($2) #incrSeqV2($1, sizeof($3));$n"
-  var a, b, dest: TLoc
+  var a, b, dest, tmpL: TLoc
   initLocExpr(p, e.sons[1], a)
   initLocExpr(p, e.sons[2], b)
   let bt = skipTypes(e.sons[2].typ, {tyVar})
@@ -1068,9 +1072,10 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
   #if bt != b.t:
   #  echo "YES ", e.info, " new: ", typeToString(bt), " old: ", typeToString(b.t)
   initLoc(dest, locExpr, bt, OnHeap)
-  dest.r = rfmt(nil, "$1->data[$1->$2]", rdLoc(a), lenField(p))
+  getIntTemp(p, tmpL)
+  lineCg(p, cpsStmts, "$1 = $2->$3++;$n", tmpL.r, rdLoc(a), lenField(p))
+  dest.r = rfmt(nil, "$1->data[$2]", rdLoc(a), tmpL.r)
   genAssignment(p, dest, b, {needToCopy, afDestIsNil})
-  lineCg(p, cpsStmts, "++$1->$2;$n", rdLoc(a), lenField(p))
   gcUsage(e)
 
 proc genReset(p: BProc, n: PNode) =
@@ -1096,9 +1101,9 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
   if a.s == OnHeap and usesNativeGC():
     # use newObjRC1 as an optimization
     if canFormAcycle(a.t):
-      linefmt(p, cpsStmts, "if ($1) #nimGCunref($1);$n", a.rdLoc)
+      linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", a.rdLoc)
     else:
-      linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", a.rdLoc)
+      linefmt(p, cpsStmts, "if ($1) { #nimGCunrefNoCycle($1); $1 = NIM_NIL; }$n", a.rdLoc)
     b.r = ropecg(p.module, "($1) #newObjRC1($2, $3)", args)
     linefmt(p, cpsStmts, "$1 = $2;$n", a.rdLoc, b.rdLoc)
   else:
@@ -1126,9 +1131,9 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) =
   initLoc(call, locExpr, dest.t, OnHeap)
   if dest.s == OnHeap and usesNativeGC():
     if canFormAcycle(dest.t):
-      linefmt(p, cpsStmts, "if ($1) #nimGCunref($1);$n", dest.rdLoc)
+      linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", dest.rdLoc)
     else:
-      linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", dest.rdLoc)
+      linefmt(p, cpsStmts, "if ($1) { #nimGCunrefNoCycle($1); $1 = NIM_NIL; }$n", dest.rdLoc)
     call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", args)
     linefmt(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc)
   else:
@@ -1170,7 +1175,10 @@ proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
 
 proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
   #echo rendertree e, " ", e.isDeepConstExpr
-  if handleConstExpr(p, e, d): return
+  # inheritance in C++ does not allow struct initialization so
+  # we skip this step here:
+  if not p.module.compileToCpp:
+    if handleConstExpr(p, e, d): return
   var tmp: TLoc
   var t = e.typ.skipTypes(abstractInst)
   getTemp(p, t, tmp)
@@ -1378,13 +1386,30 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     useStringh(p.module)
     if op == mHigh: unaryExpr(p, e, d, "($1 ? (strlen($1)-1) : -1)")
     else: unaryExpr(p, e, d, "($1 ? strlen($1) : 0)")
-  of tyString, tySequence:
+  of tyString:
     if not p.module.compileToCpp:
       if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->Sup.len-1) : -1)")
       else: unaryExpr(p, e, d, "($1 ? $1->Sup.len : 0)")
     else:
       if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->len-1) : -1)")
       else: unaryExpr(p, e, d, "($1 ? $1->len : 0)")
+  of tySequence:
+    var a, tmp: TLoc
+    initLocExpr(p, e[1], a)
+    getIntTemp(p, tmp)
+    var frmt: FormatStr
+    if not p.module.compileToCpp:
+      if op == mHigh:
+        frmt = "$1 = ($2 ? ($2->Sup.len-1) : -1);$n"
+      else:
+        frmt = "$1 = ($2 ? $2->Sup.len : 0);$n"
+    else:
+      if op == mHigh:
+        frmt = "$1 = ($2 ? ($2->len-1) : -1);$n"
+      else:
+        frmt = "$1 = ($2 ? $2->len : 0);$n"
+    lineCg(p, cpsStmts, frmt, tmp.r, rdLoc(a))
+    putIntoDest(p, d, e.typ, tmp.r)
   of tyArray:
     # YYY: length(sideeffect) is optimized away incorrectly?
     if op == mHigh: putIntoDest(p, d, e.typ, rope(lastOrd(typ)))
@@ -1742,11 +1767,23 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   of mOrd: genOrd(p, e, d)
   of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray:
     genArrayLen(p, e, d, op)
-  of mXLenStr, mXLenSeq:
+  of mXLenStr:
     if not p.module.compileToCpp:
       unaryExpr(p, e, d, "($1->Sup.len)")
     else:
       unaryExpr(p, e, d, "$1->len")
+  of mXLenSeq:
+    # see 'taddhigh.nim' for why we need to use a temporary here:
+    var a, tmp: TLoc
+    initLocExpr(p, e[1], a)
+    getIntTemp(p, tmp)
+    var frmt: FormatStr
+    if not p.module.compileToCpp:
+      frmt = "$1 = $2->Sup.len;$n"
+    else:
+      frmt = "$1 = $2->len;$n"
+    lineCg(p, cpsStmts, frmt, tmp.r, rdLoc(a))
+    putIntoDest(p, d, e.typ, tmp.r)
   of mGCref: unaryStmt(p, e, d, "#nimGCref($1);$n")
   of mGCunref: unaryStmt(p, e, d, "#nimGCunref($1);$n")
   of mSetLengthStr: genSetLengthStr(p, e, d)
@@ -2123,17 +2160,19 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
       # See tests/run/tcnstseq3 for an example that would fail otherwise.
       genAsgn(p, n, fastAsgn=p.prc != nil)
   of nkDiscardStmt:
-    if n.sons[0].kind != nkEmpty:
+    let ex = n[0]
+    if ex.kind != nkEmpty:
       genLineDir(p, n)
       var a: TLoc
-      if n[0].kind in nkCallKinds:
+      if ex.kind in nkCallKinds and (ex[0].kind != nkSym or
+                                     ex[0].sym.magic == mNone):
         # bug #6037: do not assign to a temp in C++ mode:
         incl a.flags, lfSingleUse
-        genCall(p, n[0], a)
+        genCall(p, ex, a)
         if lfSingleUse notin a.flags:
           line(p, cpsStmts, a.r & ";" & tnl)
       else:
-        initLocExpr(p, n.sons[0], a)
+        initLocExpr(p, ex, a)
   of nkAsmStmt: genAsmStmt(p, n)
   of nkTryStmt:
     if p.module.compileToCpp and optNoCppExceptions notin gGlobalOptions:
@@ -2201,20 +2240,22 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
   else:
     globalError(info, "cannot create null element for: " & $t.kind)
 
-proc getNullValueAux(p: BProc; obj, cons: PNode, result: var Rope) =
+proc getNullValueAux(p: BProc; t: PType; obj, cons: PNode, result: var Rope; count: var int) =
   case obj.kind
   of nkRecList:
-    for i in countup(0, sonsLen(obj) - 1): getNullValueAux(p, obj.sons[i], cons, result)
+    for i in countup(0, sonsLen(obj) - 1):
+      getNullValueAux(p, t, obj.sons[i], cons, result, count)
   of nkRecCase:
-    getNullValueAux(p, obj.sons[0], cons, result)
+    getNullValueAux(p, t, obj.sons[0], cons, result, count)
     for i in countup(1, sonsLen(obj) - 1):
-      getNullValueAux(p, lastSon(obj.sons[i]), cons, result)
+      getNullValueAux(p, t, lastSon(obj.sons[i]), cons, result, count)
   of nkSym:
-    if not result.isNil: result.add ", "
+    if count > 0: result.add ", "
+    inc count
     let field = obj.sym
     for i in 1..<cons.len:
       if cons[i].kind == nkExprColonExpr:
-        if cons[i][0].sym.name == field.name:
+        if cons[i][0].sym.name.id == field.name.id:
           result.add genConstExpr(p, cons[i][1])
           return
       elif i == field.position:
@@ -2225,14 +2266,32 @@ proc getNullValueAux(p: BProc; obj, cons: PNode, result: var Rope) =
   else:
     localError(cons.info, "cannot create null element for: " & $obj)
 
+proc getNullValueAuxT(p: BProc; orig, t: PType; obj, cons: PNode, result: var Rope; count: var int) =
+  var base = t.sons[0]
+  let oldRes = result
+  if not p.module.compileToCpp: result.add "{"
+  let oldcount = count
+  if base != nil:
+    base = skipTypes(base, skipPtrs)
+    getNullValueAuxT(p, orig, base, base.n, cons, result, count)
+  elif not isObjLackingTypeField(t) and not p.module.compileToCpp:
+    addf(result, "$1", [genTypeInfo(p.module, orig)])
+    inc count
+  getNullValueAux(p, t, obj, cons, result, count)
+  # do not emit '{}' as that is not valid C:
+  if oldcount == count: result = oldres
+  elif not p.module.compileToCpp: result.add "}"
+
 proc genConstObjConstr(p: BProc; n: PNode): Rope =
-  var length = sonsLen(n)
   result = nil
   let t = n.typ.skipTypes(abstractInst)
-  if not isObjLackingTypeField(t) and not p.module.compileToCpp:
-    addf(result, "{$1}", [genTypeInfo(p.module, t)])
-  getNullValueAux(p, t.n, n, result)
-  result = "{$1}$n" % [result]
+  var count = 0
+  #if not isObjLackingTypeField(t) and not p.module.compileToCpp:
+  #  addf(result, "{$1}", [genTypeInfo(p.module, t)])
+  #  inc count
+  getNullValueAuxT(p, t, t, t.n, n, result, count)
+  if p.module.compileToCpp:
+    result = "{$1}$n" % [result]
 
 proc genConstSimpleList(p: BProc, n: PNode): Rope =
   var length = sonsLen(n)
@@ -2279,6 +2338,15 @@ proc genConstExpr(p: BProc, n: PNode): Rope =
     var t = skipTypes(n.typ, abstractInst)
     if t.kind == tySequence:
       result = genConstSeq(p, n, n.typ)
+    elif t.kind == tyProc and t.callConv == ccClosure and not n.sons.isNil and
+         n.sons[0].kind == nkNilLit and n.sons[1].kind == nkNilLit:
+      # this hack fixes issue that nkNilLit is expanded to {NIM_NIL,NIM_NIL}
+      # this behaviour is needed since closure_var = nil must be
+      # expanded to {NIM_NIL,NIM_NIL}
+      # in VM closures are initialized with nkPar(nkNilLit, nkNilLit)
+      # leading to duplicate code like this:
+      # "{NIM_NIL,NIM_NIL}, {NIM_NIL,NIM_NIL}"
+      result = ~"{NIM_NIL,NIM_NIL}"
     else:
       result = genConstSimpleList(p, n)
   of nkObjConstr:
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 378951d9d..8796dd729 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -164,11 +164,11 @@ proc genBreakState(p: BProc, n: PNode) =
   if n.sons[0].kind == nkClosure:
     # XXX this produces quite inefficient code!
     initLocExpr(p, n.sons[0].sons[1], a)
-    lineF(p, cpsStmts, "if (((NI*) $1)[0] < 0) break;$n", [rdLoc(a)])
+    lineF(p, cpsStmts, "if (((NI*) $1)[1] < 0) break;$n", [rdLoc(a)])
   else:
     initLocExpr(p, n.sons[0], a)
-    # the environment is guaranteed to contain the 'state' field at offset 0:
-    lineF(p, cpsStmts, "if ((((NI*) $1.ClE_0)[0]) < 0) break;$n", [rdLoc(a)])
+    # the environment is guaranteed to contain the 'state' field at offset 1:
+    lineF(p, cpsStmts, "if ((((NI*) $1.ClE_0)[1]) < 0) break;$n", [rdLoc(a)])
   #  lineF(p, cpsStmts, "if (($1) < 0) break;$n", [rdLoc(a)])
 
 proc genVarPrototypeAux(m: BModule, sym: PSym)
diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim
index 982f88cbd..fa228ff04 100644
--- a/compiler/ccgtrav.nim
+++ b/compiler/ccgtrav.nim
@@ -72,10 +72,16 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, typ: PType) =
     let arraySize = lengthOrd(typ.sons[0])
     var i: TLoc
     getTemp(p, getSysType(tyInt), i)
+    let oldCode = p.s(cpsStmts)
     linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
             i.r, arraySize.rope)
+    let oldLen = p.s(cpsStmts).len
     genTraverseProc(c, rfmt(nil, "$1[$2]", accessor, i.r), typ.sons[1])
-    lineF(p, cpsStmts, "}$n", [])
+    if p.s(cpsStmts).len == oldLen:
+      # do not emit dummy long loops for faster debug builds:
+      p.s(cpsStmts) = oldCode
+    else:
+      lineF(p, cpsStmts, "}$n", [])
   of tyObject:
     for i in countup(0, sonsLen(typ) - 1):
       var x = typ.sons[i]
@@ -99,10 +105,16 @@ proc genTraverseProcSeq(c: var TTraversalClosure, accessor: Rope, typ: PType) =
   assert typ.kind == tySequence
   var i: TLoc
   getTemp(p, getSysType(tyInt), i)
+  let oldCode = p.s(cpsStmts)
   lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n",
       [i.r, accessor, rope(if c.p.module.compileToCpp: "len" else: "Sup.len")])
+  let oldLen = p.s(cpsStmts).len
   genTraverseProc(c, "$1->data[$2]" % [accessor, i.r], typ.sons[0])
-  lineF(p, cpsStmts, "}$n", [])
+  if p.s(cpsStmts).len == oldLen:
+    # do not emit dummy long loops for faster debug builds:
+    p.s(cpsStmts) = oldCode
+  else:
+    lineF(p, cpsStmts, "}$n", [])
 
 proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash;
                      reason: TTypeInfoReason): Rope =
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 0c81ca814..35d73aac0 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -12,6 +12,7 @@
 # ------------------------- Name Mangling --------------------------------
 
 import sighashes
+from lowerings import createObj
 
 proc isKeyword(w: PIdent): bool =
   # Nim and C++ share some keywords
@@ -122,10 +123,11 @@ const
 
 proc typeName(typ: PType): Rope =
   let typ = typ.skipTypes(irrelevantForBackend)
-  result = if typ.sym != nil and typ.kind in {tyObject, tyEnum}:
-             typ.sym.name.s.mangle.rope
-           else:
-             ~"TY"
+  result =
+    if typ.sym != nil and typ.kind in {tyObject, tyEnum}:
+      rope($typ.kind & '_' & typ.sym.name.s.mangle)
+    else:
+      rope($typ.kind)
 
 proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope =
   var t = typ
@@ -335,6 +337,7 @@ proc getTypePre(m: BModule, typ: PType; sig: SigHash): Rope =
     if result == nil: result = cacheGetType(m.typeCache, sig)
 
 proc structOrUnion(t: PType): Rope =
+  let t = t.skipTypes({tyAlias})
   (if tfUnion in t.flags: rope("union") else: rope("struct"))
 
 proc getForwardStructFormat(m: BModule): string =
@@ -473,11 +476,14 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
             if tfPacked notin rectype.flags:
               add(unionBody, "struct {")
             else:
-              addf(unionBody, CC[cCompiler].structStmtFmt,
-                [rope"struct", nil, rope(CC[cCompiler].packedPragma)])
-              add(unionBody, "{")
+              if hasAttribute in CC[cCompiler].props:
+                add(unionBody, "struct __attribute__((__packed__)){" )
+              else:
+                addf(unionBody, "#pragma pack(1)$nstruct{", [])
             add(unionBody, a)
             addf(unionBody, "} $1;$n", [sname])
+            if tfPacked in rectype.flags and hasAttribute notin CC[cCompiler].props:
+              addf(unionBody, "#pragma pack(pop)$n", [])
         else:
           add(unionBody, genRecordFieldsAux(m, k, ae, rectype, check))
       else: internalError("genRecordFieldsAux(record case branch)")
@@ -524,12 +530,16 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
   # declare the record:
   var hasField = false
 
-  var attribute: Rope =
-    if tfPacked in typ.flags: rope(CC[cCompiler].packedPragma)
-    else: nil
+  if tfPacked in typ.flags:
+    if hasAttribute in CC[cCompiler].props:
+      result = structOrUnion(typ) & " __attribute__((__packed__))"
+    else:
+      result = "#pragma pack(1)" & tnl & structOrUnion(typ)
+  else:
+    result = structOrUnion(typ)
 
-  result = ropecg(m, CC[cCompiler].structStmtFmt,
-    [structOrUnion(typ), name, attribute])
+  result.add " "
+  result.add name
 
   if typ.kind == tyObject:
 
@@ -537,7 +547,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
       if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags:
         appcg(m, result, " {$n", [])
       else:
-        appcg(m, result, " {$n#TNimType* m_type;$n", [name, attribute])
+        appcg(m, result, " {$n#TNimType* m_type;$n", [])
         hasField = true
     elif m.compileToCpp:
       appcg(m, result, " : public $1 {$n",
@@ -556,6 +566,8 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
   else:
     add(result, desc)
   add(result, "};" & tnl)
+  if tfPacked in typ.flags and hasAttribute notin CC[cCompiler].props:
+    result.add "#pragma pack(pop)" & tnl
 
 proc getTupleDesc(m: BModule, typ: PType, name: Rope,
                   check: var IntSet): Rope =
@@ -787,7 +799,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
         add(m.s[cfsTypes], recdesc)
       elif tfIncompleteStruct notin t.flags: addAbiCheck(m, t, result)
   of tySet:
-    result = getTypeName(m, t.lastSon, hashType t.lastSon) & "_Set"
+    result = $t.kind & '_' & getTypeName(m, t.lastSon, hashType t.lastSon)
     m.typeCache[sig] = result
     if not isImportedType(t):
       let s = int(getSize(t))
@@ -1083,7 +1095,8 @@ proc fakeClosureType(owner: PSym): PType =
   result = newType(tyTuple, owner)
   result.rawAddSon(newType(tyPointer, owner))
   var r = newType(tyRef, owner)
-  r.rawAddSon(newType(tyTuple, owner))
+  let obj = createObj(owner, owner.info, final=false)
+  r.rawAddSon(obj)
   result.rawAddSon(r)
 
 type
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 3797a92c2..b618837c7 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -209,7 +209,7 @@ proc genLineDir(p: BProc, t: PNode) =
   if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and
       (p.prc == nil or sfPure notin p.prc.flags):
     if freshLineInfo(p, tt.info):
-      linefmt(p, cpsStmts, "#endb($1, $2);$n",
+      linefmt(p, cpsStmts, "#endb($1, $2);$N",
               line.rope, makeCString(toFilename(tt.info)))
   elif ({optLineTrace, optStackTrace} * p.options ==
       {optLineTrace, optStackTrace}) and
@@ -345,6 +345,15 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
   result.flags = {}
   constructLoc(p, result, not needsInit)
 
+proc getIntTemp(p: BProc, result: var TLoc) =
+  inc(p.labels)
+  result.r = "T" & rope(p.labels) & "_"
+  linefmt(p, cpsLocals, "NI $1;$n", result.r)
+  result.k = locTemp
+  result.s = OnStack
+  result.t = getSysType(tyInt)
+  result.flags = {}
+
 proc initGCFrame(p: BProc): Rope =
   if p.gcFrameId > 0: result = "struct {$1} GCFRAME_;$n" % [p.gcFrameType]
 
@@ -385,7 +394,8 @@ proc assignLocalVar(p: BProc, s: PSym) =
   #assert(s.loc.k == locNone) # not yet assigned
   # this need not be fulfilled for inline procs; they are regenerated
   # for each module that uses them!
-  let decl = localVarDecl(p, s) & ";" & tnl
+  let nl = if optLineDir in gOptions: "" else: tnl
+  let decl = localVarDecl(p, s) & ";" & nl
   line(p, cpsLocals, decl)
   localDebugInfo(p, s)
 
@@ -618,11 +628,11 @@ proc initFrame(p: BProc, procname, filename: Rope): Rope =
   discard cgsym(p.module, "nimFrame")
   if p.maxFrameLen > 0:
     discard cgsym(p.module, "VarSlot")
-    result = rfmt(nil, "\tnimfrs_($1, $2, $3, $4)$N",
+    result = rfmt(nil, "\tnimfrs_($1, $2, $3, $4);$n",
                   procname, filename, p.maxFrameLen.rope,
                   p.blocks[0].frameLen.rope)
   else:
-    result = rfmt(nil, "\tnimfr_($1, $2)$N", procname, filename)
+    result = rfmt(nil, "\tnimfr_($1, $2);$n", procname, filename)
 
 proc deinitFrame(p: BProc): Rope =
   result = rfmt(p.module, "\t#popFrame();$n")
@@ -1302,6 +1312,7 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
   if b == nil or passes.skipCodegen(n): return
   var m = BModule(b)
   m.initProc.options = initProcOptions(m)
+  softRnl = if optLineDir in gOptions: noRnl else: rnl
   genStmts(m.initProc, n)
 
 proc finishModule(m: BModule) =
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 22e4b5a2c..9781a8af4 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -207,7 +207,7 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
     of "generational": result = gSelectedGC == gcGenerational
     of "go":           result = gSelectedGC == gcGo
     of "none":         result = gSelectedGC == gcNone
-    of "stack":        result = gSelectedGC == gcStack
+    of "stack", "regions": result = gSelectedGC == gcRegions
     else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
   of "opt":
     case arg.normalize
@@ -429,9 +429,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
     of "none":
       gSelectedGC = gcNone
       defineSymbol("nogc")
-    of "stack":
-      gSelectedGC= gcStack
-      defineSymbol("gcstack")
+    of "stack", "regions":
+      gSelectedGC= gcRegions
+      defineSymbol("gcregions")
     else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
   of "warnings", "w":
     if processOnOffSwitchOrList({optWarns}, arg, pass, info): listWarnings()
@@ -454,6 +454,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
     of "native", "gdb":
       incl(gGlobalOptions, optCDebug)
       gOptions = gOptions + {optLineDir} - {optEndb}
+      defineSymbol("nimTypeNames", nil) # type names are used in gdb pretty printing
       undefSymbol("endb")
     else:
       localError(info, "expected endb|gdb but found " & arg)
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index a4f47ac72..dc97e3648 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -41,7 +41,10 @@ proc isDefined*(symbol: string): bool =
       result = targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos,
                             osQnx, osAtari, osAix,
                             osHaiku, osVxWorks, osSolaris, osNetbsd,
-                            osFreebsd, osOpenbsd, osDragonfly, osMacosx}
+                            osFreebsd, osOpenbsd, osDragonfly, osMacosx,
+                            osAndroid}
+    of "linux":
+      result = targetOS in {osLinux, osAndroid}
     of "bsd":
       result = targetOS in {osNetbsd, osFreebsd, osOpenbsd, osDragonfly}
     of "emulatedthreadvars":
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 26dd889ce..3f4f7b164 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -462,12 +462,14 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
     var path = n.info.toFullPath
     if path.startsWith(cwd):
       path = path[cwd.len+1 .. ^1].replace('\\', '/')
-    var commit = getConfigVar("git.commit")
-    if commit.len == 0: commit = "master"
-    dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc,
-        ["path", "line", "url", "commit"], [rope path,
-        rope($n.info.line), rope getConfigVar("git.url"),
-        rope commit])])
+    let gitUrl = getConfigVar("git.url")
+    if gitUrl.len > 0:
+      var commit = getConfigVar("git.commit")
+      if commit.len == 0: commit = "master"
+      dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc,
+          ["path", "line", "url", "commit"], [rope path,
+          rope($n.info.line), rope gitUrl,
+          rope commit])])
 
   add(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
     ["name", "header", "desc", "itemID", "header_plain", "itemSym",
diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim
index 987cfaf42..6789df87d 100644
--- a/compiler/evalffi.nim
+++ b/compiler/evalffi.nim
@@ -104,9 +104,9 @@ proc mapCallConv(cc: TCallingConvention, info: TLineInfo): TABI =
   else:
     globalError(info, "cannot map calling convention to FFI")
 
-template rd(T, p: expr): expr {.immediate.} = (cast[ptr T](p))[]
-template wr(T, p, v: expr) {.immediate.} = (cast[ptr T](p))[] = v
-template `+!`(x, y: expr): expr {.immediate.} =
+template rd(T, p: untyped): untyped = (cast[ptr T](p))[]
+template wr(T, p, v: untyped): untyped = (cast[ptr T](p))[] = v
+template `+!`(x, y: untyped): untyped =
   cast[pointer](cast[ByteAddress](x) + y)
 
 proc packSize(v: PNode, typ: PType): int =
@@ -171,7 +171,7 @@ const maxPackDepth = 20
 var packRecCheck = 0
 
 proc pack(v: PNode, typ: PType, res: pointer) =
-  template awr(T, v: expr) {.immediate, dirty.} =
+  template awr(T, v: untyped): untyped =
     wr(T, res, v)
 
   case typ.kind
@@ -302,7 +302,7 @@ proc canonNodeKind(k: TNodeKind): TNodeKind =
   else: result = k
 
 proc unpack(x: pointer, typ: PType, n: PNode): PNode =
-  template aw(k, v, field: expr) {.immediate, dirty.} =
+  template aw(k, v, field: untyped): untyped =
     if n.isNil:
       result = newNode(k)
       result.typ = typ
@@ -326,9 +326,9 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
       result.kind = nkNilLit
       result.typ = typ
 
-  template awi(kind, v: expr) {.immediate, dirty.} = aw(kind, v, intVal)
-  template awf(kind, v: expr) {.immediate, dirty.} = aw(kind, v, floatVal)
-  template aws(kind, v: expr) {.immediate, dirty.} = aw(kind, v, strVal)
+  template awi(kind, v: untyped): untyped = aw(kind, v, intVal)
+  template awf(kind, v: untyped): untyped = aw(kind, v, floatVal)
+  template aws(kind, v: untyped): untyped = aw(kind, v, strVal)
 
   case typ.kind
   of tyBool: awi(nkIntLit, rd(bool, x).ord)
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index ca4f621e4..c47e4fb9a 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -53,7 +53,6 @@ type
                          # used on some platforms
     asmStmtFrmt: string, # format of ASM statement
     structStmtFmt: string, # Format for struct statement
-    packedPragma: string,  # Attribute/pragma to make struct packed (1-byte aligned)
     props: TInfoCCProps] # properties of the C compiler
 
 
@@ -86,7 +85,6 @@ compiler gcc:
     pic: "-fPIC",
     asmStmtFrmt: "asm($1);$n",
     structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name
-    packedPragma: "__attribute__((__packed__))",
     props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
             hasAttribute})
 
@@ -129,7 +127,6 @@ compiler vcc:
     pic: "",
     asmStmtFrmt: "__asm{$n$1$n}$n",
     structStmtFmt: "$3$n$1 $2",
-    packedPragma: "#pragma pack(1)",
     props: {hasCpp, hasAssume, hasDeclspec})
 
 # Intel C/C++ Compiler
@@ -166,7 +163,6 @@ compiler lcc:
     pic: "",
     asmStmtFrmt: "_asm{$n$1$n}$n",
     structStmtFmt: "$1 $2",
-    packedPragma: "", # XXX: not supported yet
     props: {})
 
 # Borland C Compiler
@@ -191,7 +187,6 @@ compiler bcc:
     pic: "",
     asmStmtFrmt: "__asm{$n$1$n}$n",
     structStmtFmt: "$1 $2",
-    packedPragma: "", # XXX: not supported yet
     props: {hasCpp})
 
 # Digital Mars C Compiler
@@ -216,7 +211,6 @@ compiler dmc:
     pic: "",
     asmStmtFrmt: "__asm{$n$1$n}$n",
     structStmtFmt: "$3$n$1 $2",
-    packedPragma: "#pragma pack(1)",
     props: {hasCpp})
 
 # Watcom C Compiler
@@ -241,7 +235,6 @@ compiler wcc:
     pic: "",
     asmStmtFrmt: "__asm{$n$1$n}$n",
     structStmtFmt: "$1 $2",
-    packedPragma: "", # XXX: not supported yet
     props: {hasCpp})
 
 # Tiny C Compiler
@@ -266,7 +259,6 @@ compiler tcc:
     pic: "",
     asmStmtFrmt: "__asm{$n$1$n}$n",
     structStmtFmt: "$1 $2",
-    packedPragma: "", # XXX: not supported yet
     props: {hasSwitchRange, hasComputedGoto})
 
 # Pelles C Compiler
@@ -292,7 +284,6 @@ compiler pcc:
     pic: "",
     asmStmtFrmt: "__asm{$n$1$n}$n",
     structStmtFmt: "$1 $2",
-    packedPragma: "", # XXX: not supported yet
     props: {})
 
 # Your C Compiler
@@ -317,7 +308,6 @@ compiler ucc:
     pic: "",
     asmStmtFrmt: "__asm{$n$1$n}$n",
     structStmtFmt: "$1 $2",
-    packedPragma: "", # XXX: not supported yet
     props: {})
 
 const
@@ -687,11 +677,14 @@ proc getLinkCmd(projectfile, objfiles: string): string =
     exefile = quoteShell(exefile)
     let linkOptions = getLinkOptions() & " " &
                       getConfigVar(cCompiler, ".options.linker")
+    var linkTmpl = getConfigVar(cCompiler, ".linkTmpl")
+    if linkTmpl.len == 0:
+      linkTmpl = CC[cCompiler].linkTmpl
     result = quoteShell(result % ["builddll", builddll,
         "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
         "exefile", exefile, "nim", getPrefixDir(), "lib", libpath])
     result.add ' '
-    addf(result, CC[cCompiler].linkTmpl, ["builddll", builddll,
+    addf(result, linkTmpl, ["builddll", builddll,
         "buildgui", buildgui, "options", linkOptions,
         "objfiles", objfiles, "exefile", exefile,
         "nim", quoteShell(getPrefixDir()),
diff --git a/compiler/installer.ini b/compiler/installer.ini
index 8cc89da9f..8052121bf 100644
--- a/compiler/installer.ini
+++ b/compiler/installer.ini
@@ -6,7 +6,7 @@ Name: "Nim"
 Version: "$version"
 Platforms: """
   windows: i386;amd64
-  linux: i386;amd64;powerpc64;arm;sparc;mips;mipsel;powerpc;powerpc64el;arm64
+  linux: i386;amd64;powerpc64;arm;sparc;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64
   macosx: i386;amd64;powerpc64
   solaris: i386;amd64;sparc;sparc64
   freebsd: i386;amd64
@@ -14,6 +14,7 @@ Platforms: """
   openbsd: i386;amd64
   dragonfly: i386;amd64
   haiku: i386;amd64
+  android: i386;arm;arm64
 """
 
 Authors: "Andreas Rumpf"
@@ -47,7 +48,7 @@ Start: "doc/html/overview.html"
 
 
 [Other]
-Files: "readme.txt;copying.txt"
+Files: "readme.txt;copying.txt;install.txt"
 Files: "makefile"
 Files: "koch.nim"
 Files: "install_nimble.nims"
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 46766cfcf..73e6a9948 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -2340,7 +2340,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
   of nkPragma: genPragma(p, n)
   of nkProcDef, nkMethodDef, nkConverterDef:
     var s = n.sons[namePos].sym
-    if sfExportc in s.flags and compilingLib:
+    if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}:
       genSym(p, n.sons[namePos], r)
       r.res = nil
   of nkGotoState, nkState:
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index cd2ccfe53..986d8c716 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -142,7 +142,7 @@ proc createStateField(iter: PSym): PSym =
 proc createEnvObj(owner: PSym; info: TLineInfo): PType =
   # YYY meh, just add the state field for every closure for now, it's too
   # hard to figure out if it comes from a closure iterator:
-  result = createObj(owner, info)
+  result = createObj(owner, info, final=false)
   rawAddField(result, createStateField(owner))
 
 proc getIterResult(iter: PSym): PSym =
diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim
index 4bd54603d..ce76b63a4 100644
--- a/compiler/lowerings.nim
+++ b/compiler/lowerings.nim
@@ -109,17 +109,19 @@ proc lowerSwap*(n: PNode; owner: PSym): PNode =
   result.add newFastAsgnStmt(n[1], n[2])
   result.add newFastAsgnStmt(n[2], tempAsNode)
 
-proc createObj*(owner: PSym, info: TLineInfo): PType =
+proc createObj*(owner: PSym, info: TLineInfo; final=true): PType =
   result = newType(tyObject, owner)
-  rawAddSon(result, nil)
-  incl result.flags, tfFinal
+  if final:
+    rawAddSon(result, nil)
+    incl result.flags, tfFinal
+  else:
+    rawAddSon(result, getCompilerProc("RootObj").typ)
   result.n = newNodeI(nkRecList, info)
-  when true:
-    let s = newSym(skType, getIdent("Env_" & info.toFilename),
-                   owner, info)
-    incl s.flags, sfAnon
-    s.typ = result
-    result.sym = s
+  let s = newSym(skType, getIdent("Env_" & info.toFilename),
+                  owner, info)
+  incl s.flags, sfAnon
+  s.typ = result
+  result.sym = s
 
 proc rawAddField*(obj: PType; field: PSym) =
   assert field.kind == skField
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 5f4a0caf1..4a1166f51 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -746,7 +746,7 @@ proc toFileLine*(info: TLineInfo): string {.inline.} =
   result = info.toFilename & ":" & $info.line
 
 proc toFileLineCol*(info: TLineInfo): string {.inline.} =
-  result = info.toFilename & "(" & $info.line & "," & $info.col & ")"
+  result = info.toFilename & "(" & $info.line & ", " & $info.col & ")"
 
 proc `$`*(info: TLineInfo): string = toFileLineCol(info)
 
diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim
index 5e6d843de..8042644b0 100644
--- a/compiler/nimblecmd.nim
+++ b/compiler/nimblecmd.nim
@@ -9,7 +9,7 @@
 
 ## Implements some helper procs for Nimble (Nim's package manager) support.
 
-import parseutils, strutils, strtabs, os, options, msgs
+import parseutils, strutils, strtabs, os, options, msgs, sequtils
 
 proc addPath*(path: string, info: TLineInfo) =
   if not options.searchPaths.contains(path):
@@ -21,51 +21,76 @@ proc versionSplitPos(s: string): int =
   while result > 1 and s[result] != '-': dec result
   if s[result] != '-': result = s.len
 
-const
-  latest = ""
-
-proc `<.`(a, b: string): bool =
-  # wether a has a smaller version than b:
-  if a == latest: return true
-  elif b == latest: return false
-  var i = 0
-  var j = 0
-  var verA = 0
-  var verB = 0
-  while true:
-    let ii = parseInt(a, verA, i)
-    let jj = parseInt(b, verB, j)
-    if ii <= 0 or jj <= 0:
-      # if A has no number and B has but A has no number whatsoever ("#head"),
-      # A is preferred:
-      if ii > 0 and jj <= 0 and j == 0: return true
-      if ii <= 0 and jj > 0 and i == 0: return false
-      # if A has no number left, but B has, B is preferred:  0.8 vs 0.8.3
-      return jj > 0
-    if verA < verB: return true
-    elif verA > verB: return false
-    # else: same version number; continue:
-    inc i, ii
-    inc j, jj
-    if a[i] == '.': inc i
-    if b[j] == '.': inc j
+type
+  Version = distinct string
+
+proc `$`(ver: Version): string {.borrow.}
+
+proc newVersion(ver: string): Version =
+  doAssert(ver.len == 0 or ver[0] in {'#', '\0'} + Digits,
+           "Wrong version: " & ver)
+  return Version(ver)
+
+proc isSpecial(ver: Version): bool =
+  return ($ver).len > 0 and ($ver)[0] == '#'
+
+proc `<`(ver: Version, ver2: Version): bool =
+  ## This is synced from Nimble's version module.
+
+  # Handling for special versions such as "#head" or "#branch".
+  if ver.isSpecial or ver2.isSpecial:
+    if ver2.isSpecial and ($ver2).normalize == "#head":
+      return ($ver).normalize != "#head"
+
+    if not ver2.isSpecial:
+      # `#aa111 < 1.1`
+      return ($ver).normalize != "#head"
+
+  # Handling for normal versions such as "0.1.0" or "1.0".
+  var sVer = string(ver).split('.')
+  var sVer2 = string(ver2).split('.')
+  for i in 0..max(sVer.len, sVer2.len)-1:
+    var sVerI = 0
+    if i < sVer.len:
+      discard parseInt(sVer[i], sVerI)
+    var sVerI2 = 0
+    if i < sVer2.len:
+      discard parseInt(sVer2[i], sVerI2)
+    if sVerI < sVerI2:
+      return true
+    elif sVerI == sVerI2:
+      discard
+    else:
+      return false
 
 proc addPackage(packages: StringTableRef, p: string) =
   let x = versionSplitPos(p)
   let name = p.substr(0, x-1)
-  let version = if x < p.len: p.substr(x+1) else: ""
-  if packages.getOrDefault(name) <. version:
-    packages[name] = version
+  let version = newVersion(if x < p.len: p.substr(x+1) else: "")
+  if packages.getOrDefault(name).newVersion < version or
+     (not packages.hasKey(name)):
+    packages[name] = $version
 
 iterator chosen(packages: StringTableRef): string =
   for key, val in pairs(packages):
-    let res = if val == latest: key else: key & '-' & val
+    let res = if val.len == 0: key else: key & '-' & val
     yield res
 
 proc addNimblePath(p: string, info: TLineInfo) =
-  if not contains(options.searchPaths, p):
-    message(info, hintPath, p)
-    options.lazyPaths.insert(p, 0)
+  var path = p
+  let nimbleLinks = toSeq(walkPattern(p / "*.nimble-link"))
+  if nimbleLinks.len > 0:
+    # If the user has more than one .nimble-link file then... we just ignore it.
+    # Spec for these files is available in Nimble's readme:
+    # https://github.com/nim-lang/nimble#nimble-link
+    let nimbleLinkLines = readFile(nimbleLinks[0]).splitLines()
+    path = nimbleLinkLines[1]
+    if not path.isAbsolute():
+      path = p / path
+
+  if not contains(options.searchPaths, path):
+    message(info, hintPath, path)
+    options.lazyPaths.insert(path, 0)
 
 proc addPathRec(dir: string, info: TLineInfo) =
   var packages = newStringTable(modeStyleInsensitive)
@@ -82,7 +107,17 @@ proc nimblePath*(path: string, info: TLineInfo) =
   addNimblePath(path, info)
 
 when isMainModule:
+  proc v(s: string): Version = s.newVersion
+  # #head is special in the sense that it's assumed to always be newest.
+  doAssert v"1.0" < v"#head"
+  doAssert v"1.0" < v"1.1"
+  doAssert v"1.0.1" < v"1.1"
+  doAssert v"1" < v"1.1"
+  doAssert v"#aaaqwe" < v"1.1" # We cannot assume that a branch is newer.
+  doAssert v"#a111" < v"#head"
+
   var rr = newStringTable()
+  addPackage rr, "irc-#a111"
   addPackage rr, "irc-#head"
   addPackage rr, "irc-0.1.0"
   addPackage rr, "irc"
@@ -93,5 +128,6 @@ when isMainModule:
   addPackage rr, "ab-0.1"
   addPackage rr, "justone"
 
-  for p in rr.chosen:
-    echo p
+  doAssert toSeq(rr.chosen) ==
+    @["irc-#head", "another-0.1", "ab-0.1.3", "justone"]
+
diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim
index 808159b8f..c19b41af1 100644
--- a/compiler/nimconf.nim
+++ b/compiler/nimconf.nim
@@ -152,7 +152,7 @@ proc confTok(L: var TLexer, tok: var TToken; config: ConfigRef) =
     parseDirective(L, tok, config)    # else: give the token to the parser
 
 proc checkSymbol(L: TLexer, tok: TToken) =
-  if tok.tokType notin {tkSymbol..pred(tkIntLit), tkStrLit..tkTripleStrLit}:
+  if tok.tokType notin {tkSymbol..tkInt64Lit, tkStrLit..tkTripleStrLit}:
     lexMessage(L, errIdentifierExpected, tokToStr(tok))
 
 proc parseAssignment(L: var TLexer, tok: var TToken; config: ConfigRef) =
diff --git a/compiler/options.nim b/compiler/options.nim
index bf1b04c2c..40d56aea5 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -94,7 +94,7 @@ type
     cmdRun                    # run the project via TCC backend
   TStringSeq* = seq[string]
   TGCMode* = enum             # the selected GC
-    gcNone, gcBoehm, gcGo, gcStack, gcMarkAndSweep, gcRefc,
+    gcNone, gcBoehm, gcGo, gcRegions, gcMarkAndSweep, gcRefc,
     gcV2, gcGenerational
 
   IdeCmd* = enum
@@ -291,8 +291,8 @@ proc pathSubs*(p, config: string): string =
     "projectpath", options.gProjectPath,
     "projectdir", options.gProjectPath,
     "nimcache", getNimcacheDir()])
-  if '~' in result:
-    result = result.replace("~", home)
+  if "~/" in result:
+    result = result.replace("~/", home & '/')
 
 proc toGeneratedFile*(path, ext: string): string =
   ## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 3cd1e4d92..253716247 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -685,6 +685,11 @@ proc namedParams(p: var TParser, callee: PNode,
   # progress guaranteed
   exprColonEqExprListAux(p, endTok, result)
 
+proc commandParam(p: var TParser): PNode =
+  result = parseExpr(p)
+  if p.tok.tokType == tkDo:
+    result = postExprBlocks(p, result)
+
 proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
   #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
   #|       | doBlocks
@@ -733,7 +738,7 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
         when true:
           # progress NOT guaranteed
           p.hasProgress = false
-          addSon result, parseExpr(p)
+          addSon result, commandParam(p)
           if not p.hasProgress: break
         else:
           while p.tok.tokType != tkEof:
@@ -1253,14 +1258,12 @@ proc parseExprStmt(p: var TParser): PNode =
       while true:
         getTok(p)
         optInd(p, result)
-        var e = parseExpr(p)
-        addSon(result, e)
+        addSon(result, commandParam(p))
         if p.tok.tokType != tkComma: break
     elif p.tok.indent < 0 and isExprStart(p):
       result = newNode(nkCommand, a.info, @[a])
       while true:
-        var e = parseExpr(p)
-        addSon(result, e)
+        addSon(result, commandParam(p))
         if p.tok.tokType != tkComma: break
         getTok(p)
         optInd(p, result)
diff --git a/compiler/passes.nim b/compiler/passes.nim
index 7966ee88d..bf6ce1a0a 100644
--- a/compiler/passes.nim
+++ b/compiler/passes.nim
@@ -13,7 +13,7 @@
 import
   strutils, options, ast, astalgo, llstream, msgs, platform, os,
   condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
-  nimsets, syntaxes, times, rodread, idgen, modulegraphs
+  nimsets, syntaxes, times, rodread, idgen, modulegraphs, reorder
 
 type
   TPassContext* = object of RootObj # the pass's context
@@ -202,7 +202,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
         if graph.stopCompile(): break
         var n = parseTopLevelStmt(p)
         if n.kind == nkEmpty: break
-        if sfNoForward in module.flags:
+        if {sfNoForward, sfReorder} * module.flags != {}:
           # read everything, no streaming possible
           var sl = newNodeI(nkStmtList, n.info)
           sl.add n
@@ -210,6 +210,8 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
             var n = parseTopLevelStmt(p)
             if n.kind == nkEmpty: break
             sl.add n
+          if sfReorder in module.flags:
+            sl = reorder sl
           discard processTopLevelStmt(sl, a)
           break
         elif not processTopLevelStmt(n, a): break
diff --git a/compiler/platform.nim b/compiler/platform.nim
index eb0aca186..01ddba23e 100644
--- a/compiler/platform.nim
+++ b/compiler/platform.nim
@@ -21,8 +21,8 @@ type
                     # conditionals to condsyms (end of module).
     osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
     osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osAix, osPalmos, osQnx,
-    osAmiga, osAtari, osNetware, osMacos, osMacosx, osHaiku, osVxworks, osGenode
-    osJS, osNimrodVM, osStandalone
+    osAmiga, osAtari, osNetware, osMacos, osMacosx, osHaiku, osAndroid, osVxworks
+    osGenode, osJS, osNimrodVM, osStandalone
 
 type
   TInfoOSProp* = enum
@@ -143,6 +143,10 @@ const
       objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
       scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
       props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}),
+     (name: "Android", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix}),
      (name: "VxWorks", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
       objExt: ".o", newLine: "\x0A", pathSep: ";", dirSep: "\\",
       scriptExt: ".sh", curDir: ".", exeExt: ".vxe", extSep: ".",
@@ -171,7 +175,8 @@ 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, cpuSparc64
+    cpuArm, cpuArm64, cpuJS, cpuNimrodVM, cpuAVR, cpuMSP430, cpuSparc64,
+    cpuMips64, cpuMips64el
 
 type
   TEndian* = enum
@@ -200,7 +205,9 @@ const
     (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: "sparc64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64)]
+    (name: "sparc64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64),
+    (name: "mips64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64),
+    (name: "mips64el", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64)]
 
 var
   targetCPU*, hostCPU*: TSystemCPU
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 7e1db5b29..bc3771700 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -45,7 +45,7 @@ const
     wFatal, wDefine, wUndef, wCompile, wLink, wLinksys, wPure, wPush, wPop,
     wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
     wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
-    wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
+    wLinearScanEnd, wPatterns, wEffects, wNoForward, wReorder, wComputedGoto,
     wInjectStmt, wDeprecated, wExperimental, wThis}
   lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
     wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
@@ -210,9 +210,9 @@ proc pragmaDeadCodeElim(c: PContext, n: PNode) =
   if isTurnedOn(c, n): incl(c.module.flags, sfDeadCodeElim)
   else: excl(c.module.flags, sfDeadCodeElim)
 
-proc pragmaNoForward(c: PContext, n: PNode) =
-  if isTurnedOn(c, n): incl(c.module.flags, sfNoForward)
-  else: excl(c.module.flags, sfNoForward)
+proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) =
+  if isTurnedOn(c, n): incl(c.module.flags, flag)
+  else: excl(c.module.flags, flag)
 
 proc processCallConv(c: PContext, n: PNode) =
   if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
@@ -726,6 +726,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
         incl(sym.flags, sfThread)
       of wDeadCodeElim: pragmaDeadCodeElim(c, it)
       of wNoForward: pragmaNoForward(c, it)
+      of wReorder: pragmaNoForward(c, it, sfReorder)
       of wMagic: processMagic(c, it, sym)
       of wCompileTime:
         noVal(it)
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index 7d9536625..220693f68 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -1327,7 +1327,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     
     if n.hasExplicitParams:
       put(g, tkBracketLe, "[")
-      gcomma(g, n)
+      gsemicolon(g, n)
       put(g, tkBracketRi, "]")
   of nkFormalParams:
     put(g, tkParLe, "(")
diff --git a/compiler/reorder.nim b/compiler/reorder.nim
new file mode 100644
index 000000000..a9ad1fd97
--- /dev/null
+++ b/compiler/reorder.nim
@@ -0,0 +1,102 @@
+
+import intsets, tables, ast, idents, renderer
+
+const
+  nfTempMark = nfTransf
+  nfPermMark = nfNoRewrite
+
+proc accQuoted(n: PNode): PIdent =
+  var id = ""
+  for i in 0 .. <n.len:
+    let x = n[i]
+    case x.kind
+    of nkIdent: id.add(x.ident.s)
+    of nkSym: id.add(x.sym.name.s)
+    else: discard
+  result = getIdent(id)
+
+proc addDecl(n: PNode; declares: var IntSet) =
+  case n.kind
+  of nkPostfix: addDecl(n[1], declares)
+  of nkPragmaExpr: addDecl(n[0], declares)
+  of nkIdent:
+    declares.incl n.ident.id
+  of nkSym:
+    declares.incl n.sym.name.id
+  of nkAccQuoted:
+    declares.incl accQuoted(n).id
+  else: discard
+
+proc computeDeps(n: PNode, declares, uses: var IntSet; topLevel: bool) =
+  template deps(n) = computeDeps(n, declares, uses, false)
+  template decl(n) =
+    if topLevel: addDecl(n, declares)
+  case n.kind
+  of procDefs:
+    decl(n[0])
+    for i in 1..bodyPos: deps(n[i])
+  of nkLetSection, nkVarSection, nkUsingStmt:
+    for a in n:
+      if a.kind in {nkIdentDefs, nkVarTuple}:
+        for j in countup(0, a.len-3): decl(a[j])
+        for j in a.len-2..a.len-1: deps(a[j])
+  of nkConstSection, nkTypeSection:
+    for a in n:
+      if a.len >= 3:
+        decl(a[0])
+        for i in 1..<a.len: deps(a[i])
+  of nkIdent: uses.incl n.ident.id
+  of nkSym: uses.incl n.sym.name.id
+  of nkAccQuoted: uses.incl accQuoted(n).id
+  of nkOpenSymChoice, nkClosedSymChoice:
+    uses.incl n.sons[0].sym.name.id
+  of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse:
+    for i in 0..<len(n): computeDeps(n[i], declares, uses, topLevel)
+  else:
+    for i in 0..<safeLen(n): deps(n[i])
+
+proc visit(i: int; all, res: PNode; deps: var seq[(IntSet, IntSet)]): bool =
+  let n = all[i]
+  if nfTempMark in n.flags:
+    # not a DAG!
+    return true
+  if nfPermMark notin n.flags:
+    incl n.flags, nfTempMark
+    var uses = deps[i][1]
+    for j in 0..<all.len:
+      if j != i:
+        let declares = deps[j][0]
+        for d in declares:
+          if uses.contains(d):
+            let oldLen = res.len
+            if visit(j, all, res, deps):
+              result = true
+              # rollback what we did, it turned out to be a dependency that caused
+              # trouble:
+              for k in oldLen..<res.len:
+                res.sons[k].flags = res.sons[k].flags - {nfPermMark, nfTempMark}
+              if oldLen != res.len: res.sons.setLen oldLen
+            break
+    n.flags = n.flags + {nfPermMark} - {nfTempMark}
+    res.add n
+
+proc reorder*(n: PNode): PNode =
+  result = newNodeI(nkStmtList, n.info)
+  var deps = newSeq[(IntSet, IntSet)](n.len)
+  for i in 0..<n.len:
+    deps[i][0] = initIntSet()
+    deps[i][1] = initIntSet()
+    computeDeps(n[i], deps[i][0], deps[i][1], true)
+
+  for i in 0 .. n.len-1:
+    discard visit(i, n, result, deps)
+  for i in 0..<result.len:
+    result.sons[i].flags = result.sons[i].flags - {nfTempMark, nfPermMark}
+  when false:
+    # reverse the result:
+    let L = result.len-1
+    for i in 0 .. result.len div 2:
+      result.sons[i].flags = result.sons[i].flags - {nfTempMark, nfPermMark}
+      result.sons[L - i].flags = result.sons[L - i].flags - {nfTempMark, nfPermMark}
+      swap(result.sons[i], result.sons[L - i])
+  #echo result
diff --git a/compiler/ropes.nim b/compiler/ropes.nim
index d84b59f78..358ce8a53 100644
--- a/compiler/ropes.nim
+++ b/compiler/ropes.nim
@@ -228,6 +228,7 @@ proc prepend*(a: var Rope, b: string) = a = b & a
 var
   rnl* = tnl.newRope
   softRnl* = tnl.newRope
+  noRnl* = "".newRope
 
 proc `%`*(frmt: FormatStr, args: openArray[Rope]): Rope =
   var i = 0
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 5f48e2fc5..74b074f61 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -47,11 +47,9 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     #raiseRecoverableError("")
     result = errorNode(c, n)
   if result.typ == nil or result.typ == enforceVoidContext:
-    if n.kind != nkStmtList:
-      # we cannot check for 'void' in macros ...
-      localError(n.info, errExprXHasNoType,
-                 renderTree(result, {renderNoComments}))
-      result.typ = errorType(c)
+    localError(n.info, errExprXHasNoType,
+                renderTree(result, {renderNoComments}))
+    result.typ = errorType(c)
   else:
     if efNoProcvarCheck notin flags: semProcvarCheck(c, result)
     if result.typ.kind == tyVar: result = newDeref(result)
@@ -276,41 +274,6 @@ proc semSizeof(c: PContext, n: PNode): PNode =
   n.typ = getSysType(tyInt)
   result = n
 
-proc semOf(c: PContext, n: PNode): PNode =
-  if sonsLen(n) == 3:
-    n.sons[1] = semExprWithType(c, n.sons[1])
-    n.sons[2] = semExprWithType(c, n.sons[2], {efDetermineType})
-    #restoreOldStyleType(n.sons[1])
-    #restoreOldStyleType(n.sons[2])
-    let a = skipTypes(n.sons[1].typ, abstractPtrs)
-    let b = skipTypes(n.sons[2].typ, abstractPtrs)
-    let x = skipTypes(n.sons[1].typ, abstractPtrs-{tyTypeDesc})
-    let y = skipTypes(n.sons[2].typ, abstractPtrs-{tyTypeDesc})
-
-    if x.kind == tyTypeDesc or y.kind != tyTypeDesc:
-      localError(n.info, errXExpectsObjectTypes, "of")
-    elif b.kind != tyObject or a.kind != tyObject:
-      localError(n.info, errXExpectsObjectTypes, "of")
-    else:
-      let diff = inheritanceDiff(a, b)
-      # | returns: 0 iff `a` == `b`
-      # | returns: -x iff `a` is the x'th direct superclass of `b`
-      # | returns: +x iff `a` is the x'th direct subclass of `b`
-      # | returns: `maxint` iff `a` and `b` are not compatible at all
-      if diff <= 0:
-        # optimize to true:
-        message(n.info, hintConditionAlwaysTrue, renderTree(n))
-        result = newIntNode(nkIntLit, 1)
-        result.info = n.info
-        result.typ = getSysType(tyBool)
-        return result
-      elif diff == high(int):
-        localError(n.info, errXcanNeverBeOfThisSubtype, typeToString(a))
-  else:
-    localError(n.info, errXExpectsTwoArguments, "of")
-  n.typ = getSysType(tyBool)
-  result = n
-
 proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
   internalAssert n.sonsLen == 3 and
     n[1].typ != nil and n[1].typ.kind == tyTypeDesc and
@@ -1121,9 +1084,11 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
       if ty.n != nil and ty.n.kind == nkRecList:
         let field = lookupInRecord(ty.n, i)
         if field != nil:
-          n.typ = newTypeWithSons(c, tyFieldAccessor, @[ty, field.typ])
-          n.typ.n = copyTree(n)
+          n.typ = makeTypeDesc(c, field.typ)
           return n
+          #n.typ = newTypeWithSons(c, tyFieldAccessor, @[ty, field.typ])
+          #n.typ.n = copyTree(n)
+          #return n
     else:
       tryReadingGenericParam(ty)
       return
@@ -1490,6 +1455,9 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) =
   var t = skipTypes(restype, {tyGenericInst, tyAlias})
   case t.kind
   of tyVar:
+    if n.sons[0].kind in {nkHiddenStdConv, nkHiddenSubConv}:
+      n.sons[0] = n.sons[0].sons[1]
+
     n.sons[0] = takeImplicitAddr(c, n.sons[0])
   of tyTuple:
     for i in 0.. <t.sonsLen:
@@ -1829,11 +1797,11 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
   of mDefined: result = semDefined(c, setMs(n, s), false)
   of mDefinedInScope: result = semDefined(c, setMs(n, s), true)
   of mCompiles: result = semCompiles(c, setMs(n, s), flags)
-  of mLow: result = semLowHigh(c, setMs(n, s), mLow)
-  of mHigh: result = semLowHigh(c, setMs(n, s), mHigh)
+  #of mLow: result = semLowHigh(c, setMs(n, s), mLow)
+  #of mHigh: result = semLowHigh(c, setMs(n, s), mHigh)
   of mSizeOf: result = semSizeof(c, setMs(n, s))
   of mIs: result = semIs(c, setMs(n, s), flags)
-  of mOf: result = semOf(c, setMs(n, s))
+  #of mOf: result = semOf(c, setMs(n, s))
   of mShallowCopy: result = semShallowCopy(c, n, flags)
   of mExpandToAst: result = semExpandToAst(c, n, s, flags)
   of mQuoteAst: result = semQuoteAst(c, n)
@@ -2207,9 +2175,14 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     message(n.info, warnDeprecated, "bind")
     result = semExpr(c, n.sons[0], flags)
   of nkTypeOfExpr, nkTupleTy, nkTupleClassTy, nkRefTy..nkEnumTy, nkStaticTy:
+    if c.matchedConcept != nil and n.len == 1:
+      let modifier = n.modifierTypeKindOfNode
+      if modifier != tyNone:
+        var baseType = semExpr(c, n[0]).typ.skipTypes({tyTypeDesc})
+        result.typ = c.makeTypeDesc(c.newTypeWithSons(modifier, @[baseType]))
+        return
     var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
     result.typ = makeTypeDesc(c, typ)
-    #result = symNodeFromType(c, typ, n.info)
   of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
     # check if it is an expression macro:
     checkMinSonsLen(n, 1)
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index c664f735c..8b3d9c014 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -200,6 +200,41 @@ proc isStrangeArray(t: PType): bool =
   let t = t.skipTypes(abstractInst)
   result = t.kind == tyArray and t.firstOrd != 0
 
+proc semOf(c: PContext, n: PNode): PNode =
+  if sonsLen(n) == 3:
+    n.sons[1] = semExprWithType(c, n.sons[1])
+    n.sons[2] = semExprWithType(c, n.sons[2], {efDetermineType})
+    #restoreOldStyleType(n.sons[1])
+    #restoreOldStyleType(n.sons[2])
+    let a = skipTypes(n.sons[1].typ, abstractPtrs)
+    let b = skipTypes(n.sons[2].typ, abstractPtrs)
+    let x = skipTypes(n.sons[1].typ, abstractPtrs-{tyTypeDesc})
+    let y = skipTypes(n.sons[2].typ, abstractPtrs-{tyTypeDesc})
+
+    if x.kind == tyTypeDesc or y.kind != tyTypeDesc:
+      localError(n.info, errXExpectsObjectTypes, "of")
+    elif b.kind != tyObject or a.kind != tyObject:
+      localError(n.info, errXExpectsObjectTypes, "of")
+    else:
+      let diff = inheritanceDiff(a, b)
+      # | returns: 0 iff `a` == `b`
+      # | returns: -x iff `a` is the x'th direct superclass of `b`
+      # | returns: +x iff `a` is the x'th direct subclass of `b`
+      # | returns: `maxint` iff `a` and `b` are not compatible at all
+      if diff <= 0:
+        # optimize to true:
+        message(n.info, hintConditionAlwaysTrue, renderTree(n))
+        result = newIntNode(nkIntLit, 1)
+        result.info = n.info
+        result.typ = getSysType(tyBool)
+        return result
+      elif diff == high(int):
+        localError(n.info, errXcanNeverBeOfThisSubtype, typeToString(a))
+  else:
+    localError(n.info, errXExpectsTwoArguments, "of")
+  n.typ = getSysType(tyBool)
+  result = n
+
 proc magicsAfterOverloadResolution(c: PContext, n: PNode,
                                    flags: TExprFlags): PNode =
   case n[0].sym.magic
@@ -219,6 +254,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
     result.typ = getSysType(tyString)
   of mInstantiationInfo: result = semInstantiationInfo(c, n)
   of mOrd: result = semOrd(c, n)
+  of mOf: result = semOf(c, n)
   of mHigh, mLow: result = semLowHigh(c, n, n[0].sym.magic)
   of mShallowCopy: result = semShallowCopy(c, n, flags)
   of mNBindSym: result = semBindSym(c, n)
diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim
index f4c225526..b331d05a1 100644
--- a/compiler/semobjconstr.nim
+++ b/compiler/semobjconstr.nim
@@ -44,7 +44,9 @@ proc locateFieldInInitExpr(field: PSym, initExpr: PNode): PNode =
   let fieldId = field.name.id
   for i in 1 .. <initExpr.len:
     let assignment = initExpr[i]
-    internalAssert assignment.kind == nkExprColonExpr
+    if assignment.kind != nkExprColonExpr:
+      localError(initExpr.info, "incorrect object construction syntax")
+      continue
 
     if fieldId == considerQuotedIdent(assignment[0]).id:
       return assignment
@@ -278,6 +280,9 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
   for i in 1.. <result.len:
     let field = result[i]
     if nfSem notin field.flags:
+      if field.kind != nkExprColonExpr:
+        localError(n.info, "incorrect object construction syntax")
+        continue
       let id = considerQuotedIdent(field[0])
       # This node was not processed. There are two possible reasons:
       # 1) It was shadowed by a field with the same name on the left
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 5ac2e678a..8ad8a6288 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -12,14 +12,14 @@
 discard """
   hygienic templates:
 
-    template `||` (a, b: expr): expr =
+    template `||` (a, b: untyped): untyped =
       let aa = a
       if aa: aa else: b
 
     var
       a, b: T
 
-    a || b || a
+    echo a || b || a
 
   Each evaluation context has to be different and we need to perform
   some form of preliminary symbol lookup in template definitions. Hygiene is
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index de71f1632..a7c9244cc 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -1202,6 +1202,15 @@ proc freshType(res, prev: PType): PType {.inline.} =
   else:
     result = res
 
+template modifierTypeKindOfNode(n: PNode): TTypeKind =
+  case n.kind
+  of nkVarTy: tyVar
+  of nkRefTy: tyRef
+  of nkPtrTy: tyPtr
+  of nkStaticTy: tyStatic
+  of nkTypeOfExpr: tyTypeDesc
+  else: tyNone
+
 proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
   # if n.sonsLen == 0: return newConstraint(c, tyTypeClass)
   if nfBase2 in n.flags:
@@ -1227,13 +1236,7 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
       dummyName: PNode
       dummyType: PType
 
-    let modifier = case param.kind
-      of nkVarTy: tyVar
-      of nkRefTy: tyRef
-      of nkPtrTy: tyPtr
-      of nkStaticTy: tyStatic
-      of nkTypeOfExpr: tyTypeDesc
-      else: tyNone
+    let modifier = param.modifierTypeKindOfNode
 
     if modifier != tyNone:
       dummyName = param[0]
@@ -1509,9 +1512,26 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
     dec c.inTypeContext
 
 proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
+  # source : https://en.wikipedia.org/wiki/Data_structure_alignment#x86
   m.typ.kind = kind
-  m.typ.align = size.int16
   m.typ.size = size
+  # this usually works for most basic types
+  # Assuming that since ARM, ARM64  don't support unaligned access
+  # data is aligned to type size
+  m.typ.align = size.int16
+
+  # FIXME: proper support for clongdouble should be added.
+  # long double size can be 8, 10, 12, 16 bytes depending on platform & compiler
+  if targetCPU == cpuI386 and size == 8:
+    #on Linux/BSD i386, double are aligned to 4bytes (except with -malign-double)
+    if kind in {tyFloat64, tyFloat} and
+       targetOS in {osLinux, osAndroid, osNetbsd, osFreebsd, osOpenbsd, osDragonfly}:
+      m.typ.align = 4
+    # on i386, all known compiler, 64bits ints are aligned to 4bytes (except with -malign-double)
+    elif kind in {tyInt, tyUInt, tyInt64, tyUInt64}:
+      m.typ.align = 4
+  else:
+    discard
 
 proc processMagicType(c: PContext, m: PSym) =
   case m.magic
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 6084e11c0..41596f05c 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -297,7 +297,9 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
         n.sons[i].typ = arg.typ
         n.sons[i].sons[1] = arg
     else:
-      if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo}:
+      if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo, nkElse,
+                                           nkOfBranch, nkElifBranch,
+                                           nkExceptBranch}:
         arg = c.semOperand(c, n.sons[i])
         n.sons[i] = arg
     if arg.typ != nil and arg.typ.kind == tyError: return
diff --git a/compiler/testability.nim b/compiler/testability.nim
deleted file mode 100644
index 4587a5344..000000000
--- a/compiler/testability.nim
+++ /dev/null
@@ -1,5 +0,0 @@
-template tests*(body: stmt) {.immediate.} =
-  when defined(selftest):
-    when not declared(unittest): import unittest
-    body
-
diff --git a/compiler/vm.nim b/compiler/vm.nim
index b8e6467b5..93cf66c05 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -409,6 +409,28 @@ proc recSetFlagIsRef(arg: PNode) =
   for i in 0 ..< arg.safeLen:
     arg.sons[i].recSetFlagIsRef
 
+proc setLenSeq(c: PCtx; node: PNode; newLen: int; info: TLineInfo) =
+  # FIXME: this doesn't attempt to solve incomplete
+  # support of tyPtr, tyRef in VM.
+  let typ = node.typ.skipTypes(abstractInst+{tyRange}-{tyTypeDesc})
+  let typeEntry = typ.sons[0].skipTypes(abstractInst+{tyRange}-{tyTypeDesc})
+  let typeKind = case typeEntry.kind
+  of tyUInt..tyUInt64: nkUIntLit
+  of tyRange, tyEnum, tyBool, tyChar, tyInt..tyInt64: nkIntLit
+  of tyFloat..tyFloat128: nkFloatLit
+  of tyString: nkStrLit
+  of tyObject: nkObjConstr
+  of tySequence: nkNilLit
+  of tyProc, tyTuple: nkPar
+  else: nkEmpty
+
+  let oldLen = node.len
+  setLen(node.sons, newLen)
+  if oldLen < newLen:
+    # TODO: This is still not correct for tyPtr, tyRef default value
+    for i in oldLen .. <newLen:
+      node.sons[i] = newNodeI(typeKind, info)
+
 proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
   var pc = start
   var tos = tos
@@ -1118,14 +1140,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       decodeB(rkNode)
       let newLen = regs[rb].intVal.int
       if regs[ra].node.isNil: stackTrace(c, tos, pc, errNilAccess)
-      else:
-        let oldLen = regs[ra].node.len
-        setLen(regs[ra].node.sons, newLen)
-        if oldLen < newLen:
-          # XXX This is still not entirely correct
-          # set to default value:
-          for i in oldLen .. <newLen:
-            regs[ra].node.sons[i] = newNodeI(nkEmpty, c.debug[pc])
+      else: c.setLenSeq(regs[ra].node, newLen, c.debug[pc])
     of opcReset:
       internalError(c.debug[pc], "too implement")
     of opcNarrowS:
@@ -1307,12 +1322,24 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       ensureKind(rkNode)
       if c.callsite != nil: regs[ra].node = c.callsite
       else: stackTrace(c, tos, pc, errFieldXNotFound, "callsite")
-    of opcNLineInfo:
+    of opcNGetFile:
       decodeB(rkNode)
       let n = regs[rb].node
-      createStr regs[ra]
-      regs[ra].node.strVal = n.info.toFileLineCol
-      regs[ra].node.info = c.debug[pc]
+      regs[ra].node = newStrNode(nkStrLit, n.info.toFilename)
+      regs[ra].node.info = n.info
+      regs[ra].node.typ = n.typ
+    of opcNGetLine:
+      decodeB(rkNode)
+      let n = regs[rb].node
+      regs[ra].node = newIntNode(nkIntLit, n.info.line)
+      regs[ra].node.info = n.info
+      regs[ra].node.typ = n.typ
+    of opcNGetColumn:
+      decodeB(rkNode)
+      let n = regs[rb].node
+      regs[ra].node = newIntNode(nkIntLit, n.info.col)
+      regs[ra].node.info = n.info
+      regs[ra].node.typ = n.typ
     of opcEqIdent:
       decodeBC(rkInt)
       if regs[rb].node.kind == nkIdent and regs[rc].node.kind == nkIdent:
@@ -1471,6 +1498,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       createStrKeepNode(regs[ra])
       if regs[ra].node.strVal.isNil: regs[ra].node.strVal = newStringOfCap(1000)
       storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode)
+    of opcToNarrowInt:
+      decodeBC(rkInt)
+      let mask = (1'i64 shl rc) - 1 # 0xFF
+      let signbit = 1'i64 shl (rc - 1) # 0x80
+      let toggle = mask - signbit # 0x7F
+      # algorithm: -((i8 and 0xFF) xor 0x7F) + 0x7F
+      # mask off higher bits.
+      # uses two's complement to sign-extend integer.
+      # reajust integer into desired range.
+      regs[ra].intVal = -((regs[rb].intVal and mask) xor toggle) + toggle
+
     inc pc
 
 proc execute(c: PCtx, start: int): PNode =
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index 263ec8378..7e1309e0a 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -98,7 +98,7 @@ type
     opcNError,
     opcNWarning,
     opcNHint,
-    opcNLineInfo,
+    opcNGetLine, opcNGetColumn, opcNGetFile,
     opcEqIdent,
     opcStrToIdent,
     opcIdentToStr,
@@ -136,7 +136,8 @@ type
     opcNBindSym,
     opcSetType,   # dest.typ = types[Bx]
     opcTypeTrait,
-    opcMarshalLoad, opcMarshalStore
+    opcMarshalLoad, opcMarshalStore,
+    opcToNarrowInt
 
   TBlock* = object
     label*: PSym
diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim
index b2b1ec92b..b9bbba551 100644
--- a/compiler/vmdeps.nim
+++ b/compiler/vmdeps.nim
@@ -224,12 +224,13 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
       result.add copyTree(c)
   of tyTuple:
     if inst:
-      result = newNodeX(nkTupleTy)
       # only named tuples have a node, unnamed tuples don't
       if t.n.isNil:
+        result = newNodeX(nkPar)
         for subType in t.sons:
           result.add mapTypeToAst(subType, info)
       else:
+        result = newNodeX(nkTupleTy)
         for s in t.n.sons:
           result.add newIdentDefs(s)
     else:
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index ba89f88d4..dbb8c9dcd 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -656,16 +656,17 @@ proc genNarrow(c: PCtx; n: PNode; dest: TDest) =
   let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
   # uint is uint64 in the VM, we we only need to mask the result for
   # other unsigned types:
-  if t.kind in {tyUInt8..tyUInt32}:
+  if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8):
     c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
-  elif t.kind in {tyInt8..tyInt32}:
+  elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and t.size < 8):
     c.gABC(n, opcNarrowS, dest, TRegister(t.size*8))
 
 proc genNarrowU(c: PCtx; n: PNode; dest: TDest) =
   let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
   # uint is uint64 in the VM, we we only need to mask the result for
   # other unsigned types:
-  if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32}:
+  if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32} or
+    (t.kind in {tyUInt, tyInt} and t.size < 8):
     c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
 
 proc genBinaryABCnarrow(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
@@ -875,11 +876,25 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mBitnotI:
     genUnaryABC(c, n, dest, opcBitnotInt)
     genNarrowU(c, n, dest)
-  of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64,
-     mToU8, mToU16, mToU32, mToFloat, mToBiggestFloat, mToInt,
+  of mToFloat, mToBiggestFloat, mToInt,
      mToBiggestInt, mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr,
      mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
     genConv(c, n, n.sons[1], dest)
+  of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64:
+    #genNarrowU modified
+    let t = skipTypes(n.sons[1].typ, abstractVar-{tyTypeDesc})
+    let tmp = c.genx(n.sons[1])
+    c.gABC(n, opcNarrowU, tmp, TRegister(t.size*8))
+    # assign result to dest register
+    if dest < 0: dest = c.getTemp(n.typ)
+    c.gABC(n, opcAsgnInt, dest, tmp)
+    c.freeTemp(tmp)
+  of mToU8, mToU16, mToU32:
+    let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
+    var tmp = c.genx(n.sons[1])
+    if dest < 0: dest = c.getTemp(n.typ)
+    c.gABC(n, opcToNarrowInt, dest, tmp, TRegister(t.size*8))
+    c.freeTemp(tmp)
   of mEqStr, mEqCString: genBinaryABC(c, n, dest, opcEqStr)
   of mLeStr: genBinaryABC(c, n, dest, opcLeStr)
   of mLtStr: genBinaryABC(c, n, dest, opcLtStr)
@@ -1071,7 +1086,16 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mEqIdent: genBinaryABC(c, n, dest, opcEqIdent)
   of mEqNimrodNode: genBinaryABC(c, n, dest, opcEqNimrodNode)
   of mSameNodeType: genBinaryABC(c, n, dest, opcSameNodeType)
-  of mNLineInfo: genUnaryABC(c, n, dest, opcNLineInfo)
+  of mNLineInfo:
+    case n[0].sym.name.s
+    of "getFile":
+      genUnaryABC(c, n, dest, opcNGetFile)
+    of "getLine":
+      genUnaryABC(c, n, dest, opcNGetLine)
+    of "getColumn":
+      genUnaryABC(c, n, dest, opcNGetColumn)
+    else:
+      internalAssert false
   of mNHint:
     unused(n, dest)
     genUnaryStmt(c, n, opcNHint)
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index 98fd912d8..773ab8ff5 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -55,7 +55,7 @@ type
     wFloatchecks, wNanChecks, wInfChecks,
     wAssertions, wPatterns, wWarnings,
     wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wTags,
-    wDeadCodeElim, wSafecode, wNoForward, wNoRewrite,
+    wDeadCodeElim, wSafecode, wNoForward, wReorder, wNoRewrite,
     wPragma,
     wCompileTime, wNoInit,
     wPassc, wPassl, wBorrow, wDiscardable,
@@ -143,7 +143,7 @@ const
 
     "assertions", "patterns", "warnings", "hints",
     "optimization", "raises", "writes", "reads", "size", "effects", "tags",
-    "deadcodeelim", "safecode", "noforward", "norewrite",
+    "deadcodeelim", "safecode", "noforward", "reorder", "norewrite",
     "pragma",
     "compiletime", "noinit",
     "passc", "passl", "borrow", "discardable", "fieldchecks",