summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim4
-rw-r--r--compiler/astalgo.nim4
-rw-r--r--compiler/ccgexprs.nim14
-rw-r--r--compiler/ccgstmts.nim15
-rw-r--r--compiler/ccgtypes.nim7
-rw-r--r--compiler/ccgutils.nim20
-rw-r--r--compiler/cgen.nim26
-rw-r--r--compiler/evaltempl.nim2
-rw-r--r--compiler/jsgen.nim359
-rw-r--r--compiler/msgs.nim2
-rw-r--r--compiler/options.nim3
-rw-r--r--compiler/parser.nim7
-rw-r--r--compiler/sem.nim1
-rw-r--r--compiler/semcall.nim11
-rw-r--r--compiler/semdata.nim9
-rw-r--r--compiler/semexprs.nim38
-rw-r--r--compiler/semfold.nim13
-rw-r--r--compiler/semgnrc.nim13
-rw-r--r--compiler/seminst.nim20
-rw-r--r--compiler/semmagic.nim4
-rw-r--r--compiler/sempass2.nim3
-rw-r--r--compiler/semstmts.nim50
-rw-r--r--compiler/semtypes.nim51
-rw-r--r--compiler/semtypinst.nim65
-rw-r--r--compiler/sigmatch.nim133
-rw-r--r--compiler/trees.nim9
-rw-r--r--compiler/types.nim21
-rw-r--r--compiler/vm.nim2
-rw-r--r--compiler/vmgen.nim18
-rw-r--r--doc/astspec.txt4
-rw-r--r--doc/nims.rst9
-rw-r--r--koch.nim44
-rw-r--r--lib/core/macros.nim99
-rw-r--r--lib/pure/asynchttpserver.nim2
-rw-r--r--lib/pure/asyncmacro.nim2
-rw-r--r--lib/pure/collections/tables.nim7
-rw-r--r--lib/pure/concurrency/cpuinfo.nim2
-rw-r--r--lib/pure/hashes.nim11
-rw-r--r--lib/pure/httpclient.nim3
-rw-r--r--lib/pure/json.nim2
-rw-r--r--lib/pure/math.nim36
-rw-r--r--lib/pure/parsecfg.nim1
-rw-r--r--lib/pure/parseopt.nim45
-rw-r--r--lib/pure/parseopt2.nim45
-rw-r--r--lib/pure/pegs.nim2
-rw-r--r--lib/pure/random.nim3
-rw-r--r--lib/pure/streams.nim4
-rw-r--r--lib/pure/strutils.nim4
-rw-r--r--lib/pure/times.nim2
-rw-r--r--lib/system.nim143
-rw-r--r--lib/system/alloc.nim1
-rw-r--r--lib/system/gc_common.nim7
-rw-r--r--lib/system/gc_ms.nim55
-rw-r--r--lib/system/gc_stack.nim2
-rw-r--r--lib/system/mmdisp.nim11
-rw-r--r--lib/system/repr.nim4
-rw-r--r--lib/system/reprjs.nim4
-rw-r--r--lib/system/syslocks.nim12
-rw-r--r--lib/system/threads.nim12
-rw-r--r--readme.md5
-rw-r--r--tests/arithm/tshr.nim20
-rw-r--r--tests/async/tlambda.nim3
-rw-r--r--tests/bind/tinvalidbindtypedesc.nim2
-rw-r--r--tests/bind/tnicerrorforsymchoice.nim2
-rw-r--r--tests/concepts/t3414.nim22
-rw-r--r--tests/concepts/t4982.nim18
-rw-r--r--tests/concepts/t5888.nim26
-rw-r--r--tests/concepts/t5888lib/ca.nim4
-rw-r--r--tests/concepts/t5888lib/opt.nim6
-rw-r--r--tests/concepts/t5968.nim20
-rw-r--r--tests/concepts/t5983.nim22
-rw-r--r--tests/concepts/templatesinconcepts.nim56
-rw-r--r--tests/concepts/texplain.nim18
-rw-r--r--tests/concepts/tgraph.nim39
-rw-r--r--tests/concepts/trandomvars.nim61
-rw-r--r--tests/concepts/twrapconcept.nim22
-rw-r--r--tests/errmsgs/tconceptconstraint.nim21
-rw-r--r--tests/errmsgs/tgenericconstraint.nim15
-rw-r--r--tests/fields/timplicitfieldswithpartial.nim19
-rw-r--r--tests/generics/tfakedependenttypes.nim61
-rw-r--r--tests/generics/tgenericsdefaultvalues.nim14
-rw-r--r--tests/generics/tproctypecache_falsepositive.nim17
-rw-r--r--tests/generics/treentranttypes.nim111
-rw-r--r--tests/js/tjshello.nim10
-rw-r--r--tests/js/tseqops.nim51
-rw-r--r--tests/macros/tnewlit.nim140
-rw-r--r--tests/macros/tnodecompare.nim38
-rw-r--r--tests/metatype/tmatrix4.nim39
-rw-r--r--tests/metatype/tstaticparams.nim35
-rw-r--r--tests/metatype/tstaticvector.nim54
-rw-r--r--tests/misc/tcast.nim23
-rw-r--r--tests/misc/tparseopt.nim57
-rw-r--r--tests/modules/tmismatchedvisibility.nim2
-rw-r--r--tests/overload/tstaticoverload.nim30
-rw-r--r--tests/pragmas/tused.nim2
-rw-r--r--tests/statictypes/t3784.nim20
-rw-r--r--tests/statictypes/texplicitprocparams.nim19
-rw-r--r--tests/statictypes/tpassthruarith.nim54
-rw-r--r--tests/stdlib/tmath.nim23
-rw-r--r--tests/stdlib/torderedtable.nim18
-rw-r--r--tests/testament/specs.nim3
-rw-r--r--tests/testament/tester.nim28
-rw-r--r--tests/typerel/ttypedesc_as_genericparam1.nim2
-rw-r--r--tests/typerel/ttypenoval.nim2
-rw-r--r--tests/types/t1252.nim12
-rw-r--r--tests/types/thard_tyforward.nim4
-rw-r--r--tests/vm/tnimnode.nim8
-rw-r--r--tools/niminst/niminst.nim7
108 files changed, 2260 insertions, 527 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 63b656715..6e651ed00 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -453,6 +453,7 @@ type
     nfIsRef     # this node is a 'ref' node; used for the VM
     nfPreventCg # this node should be ignored by the codegen
     nfBlockArg  # this a stmtlist appearing in a call (e.g. a do block)
+    nfFromTemplate # a top-level node returned from a template
 
   TNodeFlags* = set[TNodeFlag]
   TTypeFlag* = enum   # keep below 32 for efficiency reasons (now: beyond that)
@@ -956,7 +957,8 @@ const
     skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias}
   PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
                                       nfDotSetter, nfDotField,
-                                      nfIsRef, nfPreventCg, nfLL}
+                                      nfIsRef, nfPreventCg, nfLL,
+                                      nfFromTemplate}
   namePos* = 0
   patternPos* = 1    # empty except for term rewriting macros
   genericParamsPos* = 2
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index 1fc8b7cea..e32fff181 100644
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -219,7 +219,7 @@ proc rspaces(x: int): Rope =
 
 proc toYamlChar(c: char): string =
   case c
-  of '\0'..'\x1F', '\x80'..'\xFF': result = "\\u" & strutils.toHex(ord(c), 4)
+  of '\0'..'\x1F', '\x7F'..'\xFF': result = "\\u" & strutils.toHex(ord(c), 4)
   of '\'', '\"', '\\': result = '\\' & c
   else: result = $c
 
@@ -407,6 +407,8 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
     var istr = rspaces(indent + 2)
     result = "{$N$1\"kind\": $2" %
              [istr, makeYamlString($n.kind)]
+    when defined(useNodeIds):
+      addf(result, ",$N$1\"id\": $2", [istr, rope(n.id)])
     addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
     if maxRecDepth != 0:
       addf(result, ",$N$1\"flags\": $2", [istr, rope($n.flags)])
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index f5b99c405..043064d98 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -545,7 +545,7 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       "(($4)($1) * ($4)($2))", # MulF64
       "(($4)($1) / ($4)($2))", # DivF64
 
-      "($4)((NU$3)($1) >> (NU$3)($2))", # ShrI
+      "($4)((NU$5)($1) >> (NU$3)($2))", # ShrI
       "($4)((NU$3)($1) << (NU$3)($2))", # ShlI
       "($4)($1 & $2)",      # BitandI
       "($4)($1 | $2)",      # BitorI
@@ -585,16 +585,17 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       "($1 != $2)"]           # Xor
   var
     a, b: TLoc
-    s: BiggestInt
+    s, k: BiggestInt
   assert(e.sons[1].typ != nil)
   assert(e.sons[2].typ != nil)
   initLocExpr(p, e.sons[1], a)
   initLocExpr(p, e.sons[2], b)
   # BUGFIX: cannot use result-type here, as it may be a boolean
   s = max(getSize(a.t), getSize(b.t)) * 8
+  k = getSize(a.t) * 8
   putIntoDest(p, d, e.typ,
               binArithTab[op] % [rdLoc(a), rdLoc(b), rope(s),
-                                      getSimpleTypeDesc(p.module, e.typ)])
+                                      getSimpleTypeDesc(p.module, e.typ), rope(k)])
 
 proc genEqProc(p: BProc, e: PNode, d: var TLoc) =
   var a, b: TLoc
@@ -664,7 +665,9 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
       d.s = OnHeap
   else:
     var a: TLoc
-    let typ = skipTypes(e.sons[0].typ, abstractInst)
+    var typ = skipTypes(e.sons[0].typ, abstractInst)
+    if typ.kind in {tyUserTypeClass, tyUserTypeClassInst} and typ.isResolvedUserTypeClass:
+      typ = typ.lastSon
     if typ.kind == tyVar and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e.sons[0].kind == nkHiddenAddr:
       initLocExprSingleUse(p, e[0][0], d)
       return
@@ -2148,8 +2151,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
       # are not transformed correctly. We work around this issue (#411) here
       # by ensuring it's no inner proc (owner is a module):
       if prc.skipGenericOwner.kind == skModule and sfCompileTime notin prc.flags:
-        if (optDeadCodeElim notin gGlobalOptions and
-            sfDeadCodeElim notin getModule(prc).flags) or
+        if (not emitLazily(prc)) or
             ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
             (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
             (prc.kind == skMethod):
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index a094da783..378951d9d 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -39,13 +39,11 @@ proc genVarTuple(p: BProc, n: PNode) =
   var L = sonsLen(n)
 
   # if we have a something that's been captured, use the lowering instead:
-  var useLowering = false
   for i in countup(0, L-3):
     if n[i].kind != nkSym:
-      useLowering = true; break
-  if useLowering:
-    genStmts(p, lowerTupleUnpacking(n, p.prc))
-    return
+      genStmts(p, lowerTupleUnpacking(n, p.prc))
+      return
+
   genLineDir(p, n)
   initLocExpr(p, n.sons[L-1], tup)
   var t = tup.t.skipTypes(abstractInst)
@@ -182,10 +180,11 @@ proc genGotoVar(p: BProc; value: PNode) =
     lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope])
 
 proc genSingleVar(p: BProc, a: PNode) =
-  var v = a.sons[0].sym
-  if {sfCompileTime, sfGoto} * v.flags != {}:
+  let v = a.sons[0].sym
+  if sfCompileTime in v.flags: return
+  if sfGoto in v.flags:
     # translate 'var state {.goto.} = X' into 'goto LX':
-    if sfGoto in v.flags: genGotoVar(p, a.sons[2])
+    genGotoVar(p, a.sons[2])
     return
   var targetProc = p
   if sfGlobal in v.flags:
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 02eb5ba82..0c81ca814 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -470,7 +470,12 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
           let a = genRecordFieldsAux(m, k, "$1.$2" % [ae, sname], rectype,
                                      check)
           if a != nil:
-            add(unionBody, "struct {")
+            if tfPacked notin rectype.flags:
+              add(unionBody, "struct {")
+            else:
+              addf(unionBody, CC[cCompiler].structStmtFmt,
+                [rope"struct", nil, rope(CC[cCompiler].packedPragma)])
+              add(unionBody, "{")
             add(unionBody, a)
             addf(unionBody, "} $1;$n", [sname])
         else:
diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim
index c37a8fcdb..6a7aa8951 100644
--- a/compiler/ccgutils.nim
+++ b/compiler/ccgutils.nim
@@ -11,7 +11,7 @@
 
 import
   ast, astalgo, ropes, hashes, strutils, types, msgs, wordrecg,
-  platform, trees
+  platform, trees, options
 
 proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
   case n.kind
@@ -211,20 +211,8 @@ proc mangle*(name: string): string =
   if requiresUnderscore:
     result.add "_"
 
-proc makeLLVMString*(s: string): Rope =
-  const MaxLineLength = 64
-  result = nil
-  var res = "c\""
-  for i in countup(0, len(s) - 1):
-    if (i + 1) mod MaxLineLength == 0:
-      add(result, rope(res))
-      setLen(res, 0)
-    case s[i]
-    of '\0'..'\x1F', '\x80'..'\xFF', '\"', '\\':
-      add(res, '\\')
-      add(res, toHex(ord(s[i]), 2))
-    else: add(res, s[i])
-  add(res, "\\00\"")
-  add(result, rope(res))
+proc emitLazily*(s: PSym): bool {.inline.} =
+  result = optDeadCodeElim in gGlobalOptions or
+           sfDeadCodeElim in getModule(s).flags
 
 initTypeTables()
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index fab35c584..3797a92c2 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -47,10 +47,6 @@ proc findPendingModule(m: BModule, s: PSym): BModule =
   var ms = getModule(s)
   result = m.g.modules[ms.position]
 
-proc emitLazily(s: PSym): bool {.inline.} =
-  result = optDeadCodeElim in gGlobalOptions or
-           sfDeadCodeElim in getModule(s).flags
-
 proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) =
   result.k = k
   result.s = s
@@ -142,6 +138,13 @@ proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
 template rfmt(m: BModule, fmt: string, args: varargs[Rope]): untyped =
   ropecg(m, fmt, args)
 
+var indent = "\t".rope
+
+proc indentLine(p: BProc, r: Rope): Rope =
+  result = r
+  for i in countup(0, p.blocks.len-1):
+    prepend(result, indent)
+
 proc appcg(m: BModule, c: var Rope, frmt: FormatStr,
            args: varargs[Rope]) =
   add(c, ropecg(m, frmt, args))
@@ -154,11 +157,6 @@ proc appcg(p: BProc, s: TCProcSection, frmt: FormatStr,
            args: varargs[Rope]) =
   add(p.s(s), ropecg(p.module, frmt, args))
 
-var indent = "\t".rope
-proc indentLine(p: BProc, r: Rope): Rope =
-  result = r
-  for i in countup(0, p.blocks.len-1): prepend(result, indent)
-
 proc line(p: BProc, s: TCProcSection, r: Rope) =
   add(p.s(s), indentLine(p, r))
 
@@ -603,8 +601,18 @@ proc generateHeaders(m: BModule) =
       addf(m.s[cfsHeaders], "#include \"$1\"$N", [rope(it)])
     else:
       addf(m.s[cfsHeaders], "#include $1$N", [rope(it)])
+  add(m.s[cfsHeaders], "#undef LANGUAGE_C" & tnl)
+  add(m.s[cfsHeaders], "#undef MIPSEB" & tnl)
+  add(m.s[cfsHeaders], "#undef MIPSEL" & tnl)
+  add(m.s[cfsHeaders], "#undef PPC" & tnl)
+  add(m.s[cfsHeaders], "#undef R3000" & tnl)
+  add(m.s[cfsHeaders], "#undef R4000" & tnl)
+  add(m.s[cfsHeaders], "#undef i386" & tnl)
   add(m.s[cfsHeaders], "#undef linux" & tnl)
+  add(m.s[cfsHeaders], "#undef mips" & tnl)
   add(m.s[cfsHeaders], "#undef near" & tnl)
+  add(m.s[cfsHeaders], "#undef powerpc" & tnl)
+  add(m.s[cfsHeaders], "#undef unix" & tnl)
 
 proc initFrame(p: BProc, procname, filename: Rope): Rope =
   discard cgsym(p.module, "nimFrame")
diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim
index fda0b79dd..f088afcdb 100644
--- a/compiler/evaltempl.nim
+++ b/compiler/evaltempl.nim
@@ -155,5 +155,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode =
     #if ctx.instLines: result.info = n.info
     for i in countup(0, safeLen(body) - 1):
       evalTemplateAux(body.sons[i], args, ctx, result)
+  result.flags.incl nfFromTemplate
   result = wrapInComesFrom(n.info, result)
   dec(evalTemplateCounter)
+
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index ee35356c9..b31c3a6a7 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -94,12 +94,39 @@ type
     target: TTarget # duplicated here for faster dispatching
     unique: int    # for temp identifier generation
     blocks: seq[TBlock]
+    extraIndent: int
     up: PProc     # up the call chain; required for closure support
     declaredGlobals: IntSet
 
 template `|`(a, b: untyped): untyped {.dirty.} =
   (if p.target == targetJS: a else: b)
 
+var indent = "\t".rope
+
+proc indentLine(p: PProc, r: Rope): Rope =
+  result = r
+  var p = p
+  while true:
+    for i in countup(0, p.blocks.len - 1 + p.extraIndent):
+      prepend(result, indent)
+    if p.up == nil or p.up.prc != p.prc.owner:
+      break
+    p = p.up
+
+template line(p: PProc, added: string) =
+  add(p.body, indentLine(p, rope(added)))
+
+template line(p: PProc, added: Rope) =
+  add(p.body, indentLine(p, added))
+
+template lineF(p: PProc, frmt: FormatStr, args: varargs[Rope]) =
+  add(p.body, indentLine(p, ropes.`%`(frmt, args)))
+
+template nested(p, body) =
+  inc p.extraIndent
+  body
+  dec p.extraIndent
+
 proc newGlobals(): PGlobals =
   new(result)
   result.forwarded = @[]
@@ -129,7 +156,8 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
     module: module,
     procDef: procDef,
     g: globals,
-    target: module.target)
+    target: module.target,
+    extraIndent: int(procDef != nil))
   if procDef != nil: result.prc = procDef.sons[namePos].sym
   if result.target == targetPHP:
     result.declaredGlobals = initIntSet()
@@ -290,7 +318,7 @@ proc getTemp(p: PProc, defineInLocals: bool = true): Rope =
   if p.target == targetJS:
     result = "Tmp$1" % [rope(p.unique)]
     if defineInLocals:
-      addf(p.locals, "var $1;$n", [result])
+      add(p.locals, p.indentLine("var $1;$n" % [result]))
   else:
     result = "$$Tmp$1" % [rope(p.unique)]
 
@@ -315,9 +343,11 @@ proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
     #     tmp = b
     # tmp
     gen(p, a, x)
-    p.body.addf("if (!$1) $2 = false; else {", [x.rdLoc, r.rdLoc])
-    gen(p, b, y)
-    p.body.addf("$2 = $1; }", [y.rdLoc, r.rdLoc])
+    lineF(p, "if (!$1) $2 = false; else {", [x.rdLoc, r.rdLoc])
+    p.nested:
+      gen(p, b, y)
+      lineF(p, "$2 = $1;", [y.rdLoc, r.rdLoc])
+    line(p, "}")
 
 proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
   assert r.kind == resNone
@@ -331,9 +361,11 @@ proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
     r.res = p.getTemp
     r.kind = resVal
     gen(p, a, x)
-    p.body.addf("if ($1) $2 = true; else {", [x.rdLoc, r.rdLoc])
-    gen(p, b, y)
-    p.body.addf("$2 = $1; }", [y.rdLoc, r.rdLoc])
+    lineF(p, "if ($1) $2 = true; else {", [x.rdLoc, r.rdLoc])
+    p.nested:
+      gen(p, b, y)
+      lineF(p, "$2 = $1;", [y.rdLoc, r.rdLoc])
+    line(p, "}")
 
 type
   TMagicFrmt = array[0..3, string]
@@ -415,12 +447,10 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["", "", "Math.floor($1)", "Math.floor($1)"], # ToInt
     ["", "", "Math.floor($1)", "Math.floor($1)"], # ToBiggestInt
     ["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"],
-    ["nimBoolToStr", "nimBoolToStr", "nimBoolToStr($1)", "nimBoolToStr($1)"], [
-      "cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")",
-      "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", "cstrToNimstr",
-                                   "cstrToNimstr(($1)+\"\")",
-                                   "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr",
-      "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
+    ["nimBoolToStr", "nimBoolToStr", "nimBoolToStr($1)", "nimBoolToStr($1)"],
+    ["cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
+    ["cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
+    ["cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
     ["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"],
     ["", "", "$1", "$1"]]
 
@@ -475,18 +505,18 @@ proc unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
   r.res = frmt % [r.rdLoc]
   r.kind = resExpr
 
-proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic, ops: TMagicOps) =
+proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
   var
     x, y: TCompRes
   let i = ord(optOverflowCheck notin p.options)
-  useMagic(p, ops[op][i])
+  useMagic(p, jsOps[op][i])
   if sonsLen(n) > 2:
     gen(p, n.sons[1], x)
     gen(p, n.sons[2], y)
-    r.res = ops[op][i + 2] % [x.rdLoc, y.rdLoc]
+    r.res = jsOps[op][i + 2] % [x.rdLoc, y.rdLoc]
   else:
     gen(p, n.sons[1], r)
-    r.res = ops[op][i + 2] % [r.rdLoc]
+    r.res = jsOps[op][i + 2] % [r.rdLoc]
 
 proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
   case op
@@ -501,7 +531,7 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
       gen(p, n.sons[2], y)
       r.res = "intval($1 / $2)" % [x.rdLoc, y.rdLoc]
     else:
-      arithAux(p, n, r, op, jsOps)
+      arithAux(p, n, r, op)
   of mModI:
     if p.target == targetPHP:
       var x, y: TCompRes
@@ -509,7 +539,7 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
       gen(p, n.sons[2], y)
       r.res = "($1 % $2)" % [x.rdLoc, y.rdLoc]
     else:
-      arithAux(p, n, r, op, jsOps)
+      arithAux(p, n, r, op)
   of mShrI:
     var x, y: TCompRes
     gen(p, n.sons[1], x)
@@ -534,9 +564,9 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
       else:
         gen(p, n.sons[1], r)
     else:
-      arithAux(p, n, r, op, jsOps)
+      arithAux(p, n, r, op)
   else:
-    arithAux(p, n, r, op, jsOps)
+    arithAux(p, n, r, op)
   r.kind = resExpr
 
 proc hasFrameInfo(p: PProc): bool =
@@ -546,14 +576,14 @@ proc hasFrameInfo(p: PProc): bool =
 proc genLineDir(p: PProc, n: PNode) =
   let line = toLinenumber(n.info)
   if optLineDir in p.options:
-    addf(p.body, "// line $2 \"$1\"$n",
+    lineF(p, "// line $2 \"$1\"$n",
          [rope(toFilename(n.info)), rope(line)])
   if {optStackTrace, optEndb} * p.options == {optStackTrace, optEndb} and
       ((p.prc == nil) or sfPure notin p.prc.flags):
     useMagic(p, "endb")
-    addf(p.body, "endb($1);$n", [rope(line)])
+    lineF(p, "endb($1);$n", [rope(line)])
   elif hasFrameInfo(p):
-    addf(p.body, "F.line = $1;$n" | "$$F['line'] = $1;$n", [rope(line)])
+    lineF(p, "F.line = $1;$n" | "$$F['line'] = $1;$n", [rope(line)])
 
 proc genWhileStmt(p: PProc, n: PNode) =
   var
@@ -566,20 +596,20 @@ proc genWhileStmt(p: PProc, n: PNode) =
   p.blocks[length].id = -p.unique
   p.blocks[length].isLoop = true
   let labl = p.unique.rope
-  addf(p.body, "L$1: while (true) {$n" | "while (true) {$n", [labl])
-  gen(p, n.sons[0], cond)
-  addf(p.body, "if (!$1) break L$2;$n" | "if (!$1) goto L$2;$n",
+  lineF(p, "L$1: while (true) {$n" | "while (true) {$n", [labl])
+  p.nested: gen(p, n.sons[0], cond)
+  lineF(p, "if (!$1) break L$2;$n" | "if (!$1) goto L$2;$n",
        [cond.res, labl])
-  genStmt(p, n.sons[1])
-  addf(p.body, "}$n" | "}L$#:;$n", [labl])
+  p.nested: genStmt(p, n.sons[1])
+  lineF(p, "}$n" | "}L$#:;$n", [labl])
   setLen(p.blocks, length)
 
 proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
   if src.kind != resNone:
     if dest.kind != resNone:
-      p.body.addf("$1 = $2;$n", [dest.rdLoc, src.rdLoc])
+      lineF(p, "$1 = $2;$n", [dest.rdLoc, src.rdLoc])
     else:
-      p.body.addf("$1;$n", [src.rdLoc])
+      lineF(p, "$1;$n", [src.rdLoc])
     src.kind = resNone
     src.res = nil
 
@@ -620,8 +650,8 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
   var tmpFramePtr = rope"F"
   if optStackTrace notin p.options:
     tmpFramePtr = p.getTemp(true)
-    add(p.body, tmpFramePtr & " = framePtr;" & tnl)
-  addf(p.body, "try {$n", [])
+    line(p, tmpFramePtr & " = framePtr;" & tnl)
+  lineF(p, "try {$n", [])
   if p.target == targetPHP and p.globals == nil:
       p.globals = "global $lastJSError; global $prevJSError;".rope
   var a: TCompRes
@@ -632,18 +662,18 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
   if p.target == targetJS and catchBranchesExist:
     addf(p.body, "--excHandler;$n} catch (EXC) {$n var prevJSError = lastJSError;$n" &
         " lastJSError = EXC;$n --excHandler;$n", [])
-    add(p.body, "framePtr = $1;$n" % [tmpFramePtr])
+    line(p, "framePtr = $1;$n" % [tmpFramePtr])
   elif p.target == targetPHP:
-    addf(p.body, "} catch (Exception $$EXC) {$n $$prevJSError = $$lastJSError;$n $$lastJSError = $$EXC;$n", [])
+    lineF(p, "} catch (Exception $$EXC) {$n $$prevJSError = $$lastJSError;$n $$lastJSError = $$EXC;$n", [])
   while i < length and n.sons[i].kind == nkExceptBranch:
     let blen = sonsLen(n.sons[i])
     if blen == 1:
       # general except section:
       generalCatchBranchExists = true
-      if i > 1: addf(p.body, "else {$n", [])
+      if i > 1: lineF(p, "else {$n", [])
       gen(p, n.sons[i].sons[0], a)
       moveInto(p, a, r)
-      if i > 1: addf(p.body, "}$n", [])
+      if i > 1: lineF(p, "}$n", [])
     else:
       var orExpr: Rope = nil
       useMagic(p, "isObj")
@@ -653,30 +683,32 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
         if orExpr != nil: add(orExpr, "||")
         addf(orExpr, "isObj($2lastJSError.m_type, $1)",
              [genTypeInfo(p, n.sons[i].sons[j].typ), dollar])
-      if i > 1: add(p.body, "else ")
-      addf(p.body, "if ($1lastJSError && ($2)) {$n", [dollar, orExpr])
+      if i > 1: line(p, "else ")
+      lineF(p, "if ($1lastJSError && ($2)) {$n", [dollar, orExpr])
       gen(p, n.sons[i].sons[blen - 1], a)
       moveInto(p, a, r)
-      addf(p.body, "}$n", [])
+      lineF(p, "}$n", [])
     inc(i)
   if catchBranchesExist:
     if not generalCatchBranchExists:
       useMagic(p, "reraiseException")
-      add(p.body, "else {" & tnl & "reraiseException();" & tnl & "}" & tnl)
+      line(p, "else {" & tnl)
+      line(p, indent & "reraiseException();" & tnl)
+      line(p, "}" & tnl)
     addf(p.body, "$1lastJSError = $1prevJSError;$n", [dollar])
   if p.target == targetJS:
-    add(p.body, "} finally {" & tnl)
-    add(p.body, "framePtr = $1;$n" % [tmpFramePtr])
+    line(p, "} finally {" & tnl)
+    line(p, "framePtr = $1;$n" % [tmpFramePtr])
   if p.target == targetPHP:
     # XXX ugly hack for PHP codegen
-    add(p.body, "}" & tnl)
+    line(p, "}" & tnl)
   if i < length and n.sons[i].kind == nkFinally:
     genStmt(p, n.sons[i].sons[0])
   if p.target == targetPHP:
     # XXX ugly hack for PHP codegen
-    add(p.body, "if($lastJSError) throw($lastJSError);" & tnl)
+    line(p, "if($lastJSError) throw($lastJSError);" & tnl)
   if p.target == targetJS:
-    add(p.body, "}" & tnl)
+    line(p, "}" & tnl)
 
 proc genRaiseStmt(p: PProc, n: PNode) =
   genLineDir(p, n)
@@ -685,11 +717,11 @@ proc genRaiseStmt(p: PProc, n: PNode) =
     gen(p, n.sons[0], a)
     let typ = skipTypes(n.sons[0].typ, abstractPtrs)
     useMagic(p, "raiseException")
-    addf(p.body, "raiseException($1, $2);$n",
-         [a.rdLoc, makeJSString(typ.sym.name.s)])
+    lineF(p, "raiseException($1, $2);$n",
+             [a.rdLoc, makeJSString(typ.sym.name.s)])
   else:
     useMagic(p, "reraiseException")
-    add(p.body, "reraiseException();" & tnl)
+    line(p, "reraiseException();" & tnl)
 
 proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
   var
@@ -699,9 +731,9 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
   let stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString
   if stringSwitch and p.target == targetJS:
     useMagic(p, "toJSStr")
-    addf(p.body, "switch (toJSStr($1)) {$n", [cond.rdLoc])
+    lineF(p, "switch (toJSStr($1)) {$n", [cond.rdLoc])
   else:
-    addf(p.body, "switch ($1) {$n", [cond.rdLoc])
+    lineF(p, "switch ($1) {$n", [cond.rdLoc])
   if not isEmptyType(n.typ):
     r.kind = resVal
     r.res = getTemp(p)
@@ -715,27 +747,29 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
           var v = copyNode(e.sons[0])
           while v.intVal <= e.sons[1].intVal:
             gen(p, v, cond)
-            addf(p.body, "case $1: ", [cond.rdLoc])
+            lineF(p, "case $1:$n", [cond.rdLoc])
             inc(v.intVal)
         else:
           if stringSwitch:
             case e.kind
-            of nkStrLit..nkTripleStrLit: addf(p.body, "case $1: ",
+            of nkStrLit..nkTripleStrLit: lineF(p, "case $1:$n",
                 [makeJSString(e.strVal, false)])
             else: internalError(e.info, "jsgen.genCaseStmt: 2")
           else:
             gen(p, e, cond)
-            addf(p.body, "case $1: ", [cond.rdLoc])
-      gen(p, lastSon(it), stmt)
-      moveInto(p, stmt, r)
-      addf(p.body, "$nbreak;$n", [])
+            lineF(p, "case $1:$n", [cond.rdLoc])
+      p.nested:
+        gen(p, lastSon(it), stmt)
+        moveInto(p, stmt, r)
+        lineF(p, "break;$n", [])
     of nkElse:
-      addf(p.body, "default: $n", [])
-      gen(p, it.sons[0], stmt)
-      moveInto(p, stmt, r)
-      addf(p.body, "break;$n", [])
+      lineF(p, "default: $n", [])
+      p.nested:
+        gen(p, it.sons[0], stmt)
+        moveInto(p, stmt, r)
+        lineF(p, "break;$n", [])
     else: internalError(it.info, "jsgen.genCaseStmt")
-  addf(p.body, "}$n", [])
+  lineF(p, "}$n", [])
 
 proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
   inc(p.unique)
@@ -746,13 +780,13 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
     var sym = n.sons[0].sym
     sym.loc.k = locOther
     sym.position = idx+1
+  let labl = p.unique
+  lineF(p, "L$1: do {$n" | "", [labl.rope])
   setLen(p.blocks, idx + 1)
   p.blocks[idx].id = - p.unique # negative because it isn't used yet
-  let labl = p.unique
-  addf(p.body, "L$1: do {$n" | "", [labl.rope])
   gen(p, n.sons[1], r)
-  addf(p.body, "} while(false);$n" | "$nL$#:;$n", [labl.rope])
   setLen(p.blocks, idx)
+  lineF(p, "} while(false);$n" | "$nL$#:;$n", [labl.rope])
 
 proc genBreakStmt(p: PProc, n: PNode) =
   var idx: int
@@ -770,19 +804,23 @@ proc genBreakStmt(p: PProc, n: PNode) =
     if idx < 0 or not p.blocks[idx].isLoop:
       internalError(n.info, "no loop to break")
   p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
-  addf(p.body, "break L$1;$n" | "goto L$1;$n", [rope(p.blocks[idx].id)])
+  lineF(p, "break L$1;$n" | "goto L$1;$n", [rope(p.blocks[idx].id)])
 
 proc genAsmOrEmitStmt(p: PProc, n: PNode) =
   genLineDir(p, n)
+  p.body.add p.indentLine(nil)
   for i in countup(0, sonsLen(n) - 1):
     case n.sons[i].kind
-    of nkStrLit..nkTripleStrLit: add(p.body, n.sons[i].strVal)
+    of nkStrLit..nkTripleStrLit:
+      p.body.add(n.sons[i].strVal)
     of nkSym:
       let v = n.sons[i].sym
       if p.target == targetPHP and v.kind in {skVar, skLet, skTemp, skConst, skResult, skParam, skForVar}:
-        add(p.body, "$")
-      add(p.body, mangleName(v, p.target))
-    else: internalError(n.sons[i].info, "jsgen: genAsmOrEmitStmt()")
+        p.body.add "$"
+      p.body.add mangleName(v, p.target)
+    else:
+      internalError(n.sons[i].info, "jsgen: genAsmOrEmitStmt()")
+  p.body.add tnl
 
 proc genIf(p: PProc, n: PNode, r: var TCompRes) =
   var cond, stmt: TCompRes
@@ -794,18 +832,18 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) =
     let it = n.sons[i]
     if sonsLen(it) != 1:
       if i > 0:
-        addf(p.body, "else {$n", [])
+        lineF(p, "else {$n", [])
         inc(toClose)
-      gen(p, it.sons[0], cond)
-      addf(p.body, "if ($1) {$n", [cond.rdLoc])
+      p.nested: gen(p, it.sons[0], cond)
+      lineF(p, "if ($1) {$n", [cond.rdLoc])
       gen(p, it.sons[1], stmt)
     else:
       # else part:
-      addf(p.body, "else {$n", [])
-      gen(p, it.sons[0], stmt)
+      lineF(p, "else {$n", [])
+      p.nested: gen(p, it.sons[0], stmt)
     moveInto(p, stmt, r)
-    addf(p.body, "}$n", [])
-  add(p.body, repeat('}', toClose) & tnl)
+    lineF(p, "}$n", [])
+  line(p, repeat('}', toClose) & tnl)
 
 proc generateHeader(p: PProc, typ: PType): Rope =
   result = nil
@@ -854,7 +892,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
     gen(p, x[0], a)
     gen(p, x[1], b)
     gen(p, y, c)
-    addf(p.body, "$#[$#] = chr($#);$n", [a.rdLoc, b.rdLoc, c.rdLoc])
+    lineF(p, "$#[$#] = chr($#);$n", [a.rdLoc, b.rdLoc, c.rdLoc])
     return
 
   var xtyp = mapType(p, x.typ)
@@ -862,7 +900,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
   if x.kind == nkHiddenDeref and x.sons[0].kind == nkCall and xtyp != etyObject:
     gen(p, x.sons[0], a)
     let tmp = p.getTemp(false)
-    addf(p.body, "var $1 = $2;$n", [tmp, a.rdLoc])
+    lineF(p, "var $1 = $2;$n", [tmp, a.rdLoc])
     a.res = "$1[0][$1[1]]" % [tmp]
   else:
     gen(p, x, a)
@@ -876,29 +914,29 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
   case xtyp
   of etySeq:
     if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
-      addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
+      lineF(p, "$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)])
+      lineF(p, "$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])
+      lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
     else:
       useMagic(p, "nimCopy")
-      addf(p.body, "nimCopy($1, $2, $3);$n",
-           [a.res, b.res, genTypeInfo(p, y.typ)])
+      lineF(p, "nimCopy($1, $2, $3);$n",
+               [a.res, b.res, genTypeInfo(p, y.typ)])
   of etyBaseIndex:
     if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
       if y.kind == nkCall:
         let tmp = p.getTemp(false)
-        addf(p.body, "var $1 = $4; $2 = $1[0]; $3 = $1[1];$n", [tmp, a.address, a.res, b.rdLoc])
+        lineF(p, "var $1 = $4; $2 = $1[0]; $3 = $1[1];$n", [tmp, a.address, a.res, b.rdLoc])
       else:
         internalError(x.info, "genAsgn")
     else:
-      addf(p.body, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
+      lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
   else:
-    addf(p.body, "$1 = $2;$n", [a.res, b.res])
+    lineF(p, "$1 = $2;$n", [a.res, b.res])
 
 proc genAsgn(p: PProc, n: PNode) =
   genLineDir(p, n)
@@ -906,7 +944,15 @@ proc genAsgn(p: PProc, n: PNode) =
 
 proc genFastAsgn(p: PProc, n: PNode) =
   genLineDir(p, n)
-  genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=true)
+  # 'shallowCopy' always produced 'noCopyNeeded = true' here but this is wrong
+  # for code like
+  #  while j >= pos:
+  #    dest[i].shallowCopy(dest[j])
+  # See bug #5933. So we try to be more compatible with the C backend semantics
+  # here for 'shallowCopy'. This is an educated guess and might require further
+  # changes later:
+  let noCopy = n[0].typ.skipTypes(abstractInst).kind in {tySequence, tyString}
+  genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=noCopy)
 
 proc genSwap(p: PProc, n: PNode) =
   var a, b: TCompRes
@@ -917,12 +963,13 @@ proc genSwap(p: PProc, n: PNode) =
     let tmp2 = p.getTemp(false)
     if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
       internalError(n.info, "genSwap")
-    addf(p.body, "var $1 = $2; $2 = $3; $3 = $1;$n" |
-                 "$1 = $2; $2 = $3; $3 = $1;$n", [
-                 tmp, a.address, b.address])
+    lineF(p, "var $1 = $2; $2 = $3; $3 = $1;$n" |
+             "$1 = $2; $2 = $3; $3 = $1;$n",
+             [tmp, a.address, b.address])
     tmp = tmp2
-  addf(p.body, "var $1 = $2; $2 = $3; $3 = $1;" |
-               "$1 = $2; $2 = $3; $3 = $1;", [tmp, a.res, b.res])
+  lineF(p, "var $1 = $2; $2 = $3; $3 = $1;" |
+           "$1 = $2; $2 = $3; $3 = $1;",
+           [tmp, a.res, b.res])
 
 proc getFieldPosition(f: PNode): int =
   case f.kind
@@ -1483,10 +1530,10 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
     s: Rope
   if n.kind == nkEmpty:
     let mname = mangleName(v, p.target)
-    addf(p.body, "var $1 = $2;$n" | "$$$1 = $2;$n",
-         [mname, createVar(p, v.typ, isIndirect(v))])
+    lineF(p, "var $1 = $2;$n" | "$$$1 = $2;$n",
+             [mname, createVar(p, v.typ, isIndirect(v))])
     if v.typ.kind in { tyVar, tyPtr, tyRef } and mapType(p, v.typ) == etyBaseIndex:
-      addf(p.body, "var $1_Idx = 0;$n", [ mname ])
+      lineF(p, "var $1_Idx = 0;$n", [ mname ])
   else:
     discard mangleName(v, p.target)
     gen(p, n, a)
@@ -1501,25 +1548,25 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
       let targetBaseIndex = {sfAddrTaken, sfGlobal} * v.flags == {}
       if a.typ == etyBaseIndex:
         if targetBaseIndex:
-          addf(p.body, "var $1 = $2, $1_Idx = $3;$n", [
-              v.loc.r, a.address, a.res])
+          lineF(p, "var $1 = $2, $1_Idx = $3;$n",
+                   [v.loc.r, a.address, a.res])
         else:
-          addf(p.body, "var $1 = [$2, $3];$n",
-              [v.loc.r, a.address, a.res])
+          lineF(p, "var $1 = [$2, $3];$n",
+                   [v.loc.r, a.address, a.res])
       else:
         if targetBaseIndex:
           let tmp = p.getTemp
-          addf(p.body, "var $1 = $2, $3 = $1[0], $3_Idx = $1[1];$n",
-              [tmp, a.res, v.loc.r])
+          lineF(p, "var $1 = $2, $3 = $1[0], $3_Idx = $1[1];$n",
+                   [tmp, a.res, v.loc.r])
         else:
-          addf(p.body, "var $1 = $2;$n", [v.loc.r, a.res])
+          lineF(p, "var $1 = $2;$n", [v.loc.r, a.res])
       return
     else:
       s = a.res
     if isIndirect(v):
-      addf(p.body, "var $1 = /**/[$2];$n", [v.loc.r, s])
+      lineF(p, "var $1 = [$2];$n", [v.loc.r, s])
     else:
-      addf(p.body, "var $1 = $2;$n" | "$$$1 = $2;$n", [v.loc.r, s])
+      lineF(p, "var $1 = $2;$n" | "$$$1 = $2;$n", [v.loc.r, s])
 
 proc genVarStmt(p: PProc, n: PNode) =
   for i in countup(0, sonsLen(n) - 1):
@@ -1550,17 +1597,17 @@ proc genNew(p: PProc, n: PNode) =
   gen(p, n.sons[1], a)
   var t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
   if p.target == targetJS:
-    addf(p.body, "$1 = $2;$n", [a.res, createVar(p, t, false)])
+    lineF(p, "$1 = $2;$n", [a.res, createVar(p, t, false)])
   else:
-    addf(p.body, "$3 = $2; $1 = &$3;$n", [a.res, createVar(p, t, false), getTemp(p)])
+    lineF(p, "$3 = $2; $1 = &$3;$n", [a.res, createVar(p, t, false), getTemp(p)])
 
 proc genNewSeq(p: PProc, n: PNode) =
   var x, y: TCompRes
   gen(p, n.sons[1], x)
   gen(p, n.sons[2], y)
   let t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
-  addf(p.body, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}" |
-               "$1 = array(); for ($$i=0;$$i<$2;++$$i) {$1[]=$3;}", [
+  lineF(p, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}" |
+           "$1 = array(); for ($$i=0;$$i<$2;++$$i) {$1[]=$3;}", [
     x.rdLoc, y.rdLoc, createVar(p, t, false)])
 
 proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
@@ -1716,8 +1763,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
       binaryExpr(p, n, r, "addChar",
           "if ($1 != null) { addChar($1, $2); } else { $1 = [$2, 0]; }")
     else:
-      binaryExpr(p, n, r, "",
-          "$1 .= chr($2)")
+      binaryExpr(p, n, r, "", "$1 .= chr($2)")
   of mAppendStrStr:
     if p.target == targetJS:
       if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:
@@ -1727,15 +1773,23 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
           "if ($1 != null) { $1 = ($1.slice(0, -1)).concat($2); } else { $1 = $2;}")
       # XXX: make a copy of $2, because of Javascript's sucking semantics
     else:
-      binaryExpr(p, n, r, "",
-          "$1 .= $2;")
+      binaryExpr(p, n, r, "", "$1 .= $2;")
   of mAppendSeqElem:
     if p.target == targetJS:
-      binaryExpr(p, n, r, "",
-          "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }")
+      var x, y: TCompRes
+      gen(p, n.sons[1], x)
+      gen(p, n.sons[2], y)
+      if needsNoCopy(p, n[2]):
+        r.res = "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }" % [x.rdLoc, y.rdLoc]
+      else:
+        useMagic(p, "nimCopy")
+        let c = getTemp(p, defineInLocals=false)
+        lineF(p, "var $1 = nimCopy(null, $2, $3);$n",
+             [c, y.rdLoc, genTypeInfo(p, n[2].typ)])
+        r.res = "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }" % [x.rdLoc, c]
+      r.kind = resExpr
     else:
-      binaryExpr(p, n, r, "",
-          "$1[] = $2")
+      binaryExpr(p, n, r, "", "$1[] = $2")
   of mConStrStr:
     if p.target == targetJS:
       genConStrStr(p, n, r)
@@ -1795,7 +1849,14 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
       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" | "$1 = substr($1, 0, $2)")
-  of mSetLengthSeq: binaryExpr(p, n, r, "", "$1.length = $2" | "$1 = array_slice($1, 0, $2)")
+  of mSetLengthSeq:
+    var x, y: TCompRes
+    gen(p, n.sons[1], x)
+    gen(p, n.sons[2], y)
+    let t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
+    r.res = """if ($1.length < $2) { for (var i=$1.length;i<$2;++i) $1.push($3); }
+               else { $1.length = $2; }""" % [x.rdLoc, y.rdLoc, createVar(p, t, false)]
+    r.kind = resExpr
   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)")
@@ -1986,15 +2047,18 @@ proc genReturnStmt(p: PProc, n: PNode) =
     genStmt(p, n.sons[0])
   else:
     genLineDir(p, n)
-  addf(p.body, "break BeforeRet;$n" | "goto BeforeRet;$n", [])
+  lineF(p, "break BeforeRet;$n" | "goto BeforeRet;$n", [])
 
 proc frameCreate(p: PProc; procname, filename: Rope): Rope =
-  result = (("var F={procname:$1,prev:framePtr,filename:$2,line:0};$nframePtr = F;$n" |
-             "global $$framePtr; $$F=array('procname'=>$#,'prev'=>$$framePtr,'filename'=>$#,'line'=>0);$n$$framePtr = &$$F;$n")) % [
-            procname, filename]
+  let frameFmt =
+    "var F={procname:$1,prev:framePtr,filename:$2,line:0};$n" |
+    "global $$framePtr; $$F=array('procname'=>$#,'prev'=>$$framePtr,'filename'=>$#,'line'=>0);$n"
+
+  result = p.indentLine(frameFmt % [procname, filename])
+  result.add p.indentLine(ropes.`%`("framePtr = F;$n" | "$$framePtr = &$$F;$n", []))
 
 proc frameDestroy(p: PProc): Rope =
-  result = rope(("framePtr = F.prev;" | "$framePtr = $F['prev'];") & tnl)
+  result = p.indentLine rope(("framePtr = F.prev;" | "$framePtr = $F['prev'];") & tnl)
 
 proc genProcBody(p: PProc, prc: PSym): Rope =
   if hasFrameInfo(p):
@@ -2004,8 +2068,12 @@ proc genProcBody(p: PProc, prc: PSym): Rope =
   else:
     result = nil
   if p.beforeRetNeeded:
-    addf(result, "BeforeRet: do {$n$1} while (false); $n" |
-                 "$# BeforeRet:;$n", [p.body])
+    if p.target == targetJS:
+      result.add p.indentLine(~"BeforeRet: do {$n")
+      result.add p.body
+      result.add p.indentLine(~"} while (false);$n")
+    else:
+      addF(result, "$# BeforeRet:;$n", [p.body])
   else:
     add(result, p.body)
   if prc.typ.callConv == ccSysCall and p.target == targetJS:
@@ -2014,6 +2082,12 @@ proc genProcBody(p: PProc, prc: PSym): Rope =
   if hasFrameInfo(p):
     add(result, frameDestroy(p))
 
+proc optionaLine(p: Rope): Rope =
+  if p == nil:
+    return nil
+  else:
+    return p & tnl
+
 proc genProc(oldProc: PProc, prc: PSym): Rope =
   var
     resultSym: PSym
@@ -2029,29 +2103,37 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
   if prc.typ.sons[0] != nil and sfPure notin prc.flags:
     resultSym = prc.ast.sons[resultPos].sym
     let mname = mangleName(resultSym, p.target)
-    resultAsgn = ("var $# = $#;$n" | "$$$# = $#;$n") % [
-        mname,
-        createVar(p, resultSym.typ, isIndirect(resultSym))]
+    let resVar = createVar(p, resultSym.typ, isIndirect(resultSym))
+    resultAsgn = p.indentLine(("var $# = $#;$n" | "$$$# = $#;$n") % [mname, resVar])
     if resultSym.typ.kind in { tyVar, tyPtr, tyRef } and mapType(p, resultSym.typ) == etyBaseIndex:
-      resultAsgn.add "var $#_Idx = 0;$n" % [
-        mname ];
+      resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname])
     gen(p, prc.ast.sons[resultPos], a)
     if mapType(p, resultSym.typ) == etyBaseIndex:
       returnStmt = "return [$#, $#];$n" % [a.address, a.res]
     else:
       returnStmt = "return $#;$n" % [a.res]
-  genStmt(p, prc.getBody)
 
-  result = "function $#($#) {$n$#$n$#$#$#$#}$n" %
-            [name, header, p.globals, p.locals, resultAsgn,
-             genProcBody(p, prc), returnStmt]
+  p.nested: genStmt(p, prc.getBody)
+  let def = "function $#($#) {$n$#$#$#$#$#" %
+            [name, header,
+              optionaLine(p.globals),
+              optionaLine(p.locals),
+              optionaLine(resultAsgn),
+              optionaLine(genProcBody(p, prc)),
+              optionaLine(p.indentLine(returnStmt))]
+
+  dec p.extraIndent
+  result = ~tnl
+  result.add p.indentLine(def)
+  result.add p.indentLine(~"}$n")
+
   #if gVerbosity >= 3:
   #  echo "END   generated code for: " & prc.name.s
 
 proc genStmt(p: PProc, n: PNode) =
   var r: TCompRes
   gen(p, n, r)
-  if r.res != nil: addf(p.body, "$#;$n", [r.res])
+  if r.res != nil: lineF(p, "$#;$n", [r.res])
 
 proc genPragma(p: PProc, n: PNode) =
   for it in n.sons:
@@ -2211,7 +2293,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, sfCompilerProc} * s.flags == {sfExportc}:
+    if sfExportc in s.flags and compilingLib:
       genSym(p, n.sons[namePos], r)
       r.res = nil
   of nkGotoState, nkState:
@@ -2342,3 +2424,4 @@ proc myOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext =
   result = r
 
 const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
+
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index e416a3826..5f4a0caf1 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -543,7 +543,7 @@ var
 
 proc toCChar*(c: char): string =
   case c
-  of '\0'..'\x1F', '\x80'..'\xFF': result = '\\' & toOctal(c)
+  of '\0'..'\x1F', '\x7F'..'\xFF': result = '\\' & toOctal(c)
   of '\'', '\"', '\\', '?': result = '\\' & c
   else: result = $(c)
 
diff --git a/compiler/options.nim b/compiler/options.nim
index c4a57f41c..5c39faf3b 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -186,6 +186,9 @@ var
 
 const oKeepVariableNames* = true
 
+template compilingLib*: bool =
+  gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}
+
 proc mainCommandArg*: string =
   ## This is intended for commands like check or parse
   ## which will work on the main project file unless
diff --git a/compiler/parser.nim b/compiler/parser.nim
index d4c44788e..8bd99acd3 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -846,6 +846,7 @@ type
   TDeclaredIdentFlag = enum
     withPragma,               # identifier may have pragma
     withBothOptional          # both ':' and '=' parts are optional
+    withDot                   # allow 'var ident.ident = value'
   TDeclaredIdentFlags = set[TDeclaredIdentFlag]
 
 proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
@@ -859,7 +860,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
   while true:
     case p.tok.tokType
     of tkSymbol, tkAccent:
-      if withPragma in flags: a = identWithPragma(p)
+      if withPragma in flags: a = identWithPragma(p, allowDot=withdot in flags)
       else: a = parseSymbol(p)
       if a.kind == nkEmpty: return
     else: break
@@ -1889,7 +1890,7 @@ proc parseVarTuple(p: var TParser): PNode =
   optInd(p, result)
   # progress guaranteed
   while p.tok.tokType in {tkSymbol, tkAccent}:
-    var a = identWithPragma(p)
+    var a = identWithPragma(p, allowDot=true)
     addSon(result, a)
     if p.tok.tokType != tkComma: break
     getTok(p)
@@ -1905,7 +1906,7 @@ proc parseVariable(p: var TParser): PNode =
   #| colonBody = colcom stmt doBlocks?
   #| variable = (varTuple / identColonEquals) colonBody? indAndComment
   if p.tok.tokType == tkParLe: result = parseVarTuple(p)
-  else: result = parseIdentColonEquals(p, {withPragma})
+  else: result = parseIdentColonEquals(p, {withPragma, withDot})
   result{-1} = postExprBlocks(p, result{-1})
   indAndComment(p, result)
 
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 9f80e1399..cd0df0de0 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -442,6 +442,7 @@ proc semConstBoolExpr(c: PContext, n: PNode): PNode =
     result = nn
 
 proc semGenericStmt(c: PContext, n: PNode): PNode
+proc semConceptBody(c: PContext, n: PNode): PNode
 
 include semtypes, semtempl, semgnrc, semstmts, semexprs
 
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 4fa4f7f32..5984e25e0 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -408,7 +408,13 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
     else:
       # get rid of the deref again for a better error message:
       n.sons[1] = n.sons[1].sons[0]
-      notFoundError(c, n, errors)
+      #notFoundError(c, n, errors)
+      if efExplain notin flags:
+        # repeat the overload resolution,
+        # this time enabling all the diagnostic output (this should fail again)
+        discard semOverloadedCall(c, n, nOrig, filter, flags + {efExplain})
+      else:
+        notFoundError(c, n, errors)
   else:
     if efExplain notin flags:
       # repeat the overload resolution,
@@ -440,7 +446,8 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
 proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
   assert n.kind == nkBracketExpr
   for i in 1..sonsLen(n)-1:
-    n.sons[i].typ = semTypeNode(c, n.sons[i], nil)
+    let e = semExpr(c, n.sons[i])
+    n.sons[i].typ = e.typ.skipTypes({tyTypeDesc})
   var s = s
   var a = n.sons[0]
   if a.kind == nkSym:
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 5da2b70fa..d422646a8 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -40,6 +40,11 @@ type
     bracketExpr*: PNode       # current bracket expression (for ^ support)
     mapping*: TIdTable
 
+  TMatchedConcept* = object
+    candidateType*: PType
+    prev*: ptr TMatchedConcept
+    depth*: int
+
   TInstantiationPair* = object
     genericSym*: PSym
     inst*: PInstantiation
@@ -75,6 +80,7 @@ type
     importTable*: PScope       # scope for all imported symbols
     topLevelScope*: PScope     # scope for all top-level symbols
     p*: PProcCon               # procedure context
+    matchedConcept*: ptr TMatchedConcept # the current concept being matched
     friendModules*: seq[PSym]  # friend modules; may access private data;
                                # this is used so that generic instantiations
                                # can access private object fields
@@ -82,7 +88,6 @@ type
 
     ambiguousSymbols*: IntSet  # ids of all ambiguous symbols (cannot
                                # store this info in the syms themselves!)
-    inTypeClass*: int          # > 0 if we are in a user-defined type class
     inGenericContext*: int     # > 0 if we are in a generic type
     inUnrolledContext*: int    # > 0 if we are unrolling a loop
     compilesContextId*: int    # > 0 if we are in a ``compiles`` magic
@@ -277,7 +282,7 @@ proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
   assert n != nil
   result.n = n
 
-proc newTypeWithSons2*(kind: TTypeKind, owner: PSym, sons: seq[PType]): PType =
+proc newTypeWithSons*(owner: PSym, kind: TTypeKind, sons: seq[PType]): PType =
   result = newType(kind, owner)
   result.sons = sons
 
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 59fa208d2..08a2e2ce9 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -106,7 +106,10 @@ proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
       result = convNotNeedeed
     return
   var d = skipTypes(castDest, abstractVar)
-  var s = skipTypes(src, abstractVar-{tyTypeDesc})
+  var s = src
+  if s.kind in tyUserTypeClasses and s.isResolvedUserTypeClass:
+    s = s.lastSon
+  s = skipTypes(s, abstractVar-{tyTypeDesc})
   var pointers = 0
   while (d != nil) and (d.kind in {tyPtr, tyRef}) and (d.kind == s.kind):
     d = d.lastSon
@@ -152,6 +155,8 @@ proc isCastable(dst, src: PType): bool =
     result = false
   elif typeAllowed(dst, skParam) != nil:
     result = false
+  elif dst.kind == tyProc and dst.callConv == ccClosure:
+    result = src.kind == tyProc and src.callConv == ccClosure
   else:
     result = (dstSize >= srcSize) or
         (skipTypes(dst, abstractInst).kind in IntegralTypes) or
@@ -227,7 +232,10 @@ proc semCast(c: PContext, n: PNode): PNode =
   if tfHasMeta in targetType.flags:
     localError(n.sons[0].info, errCastToANonConcreteType, $targetType)
   if not isCastable(targetType, castedExpr.typ):
-    localError(n.info, errExprCannotBeCastToX, $targetType)
+    let tar = $targetType
+    let alt = typeToString(targetType, preferDesc)
+    let msg = if tar != alt: tar & "=" & alt else: tar
+    localError(n.info, errExprCannotBeCastToX, msg)
   result = newNodeI(nkCast, n.info)
   result.typ = targetType
   addSon(result, copyTree(n.sons[0]))
@@ -700,7 +708,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
     analyseIfAddressTakenInCall(c, result)
     if callee.magic != mNone:
       result = magicsAfterOverloadResolution(c, result, flags)
-  if c.inTypeClass == 0:
+  if c.matchedConcept == nil:
     result = evalAtCompileTime(c, result)
 
 proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
@@ -880,20 +888,6 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
     if r.sym.name.id == field.id: result = r.sym
   else: illFormedAst(n)
 
-proc makeDeref(n: PNode): PNode =
-  var t = skipTypes(n.typ, {tyGenericInst, tyAlias})
-  result = n
-  if t.kind == tyVar:
-    result = newNodeIT(nkHiddenDeref, n.info, t.sons[0])
-    addSon(result, n)
-    t = skipTypes(t.sons[0], {tyGenericInst, tyAlias})
-  while t.kind in {tyPtr, tyRef}:
-    var a = result
-    let baseTyp = t.lastSon
-    result = newNodeIT(nkHiddenDeref, n.info, baseTyp)
-    addSon(result, a)
-    t = skipTypes(baseTyp, {tyGenericInst, tyAlias})
-
 const
   tyTypeParamsHolders = {tyGenericInst, tyCompositeTypeClass}
   tyDotOpTransparent = {tyVar, tyPtr, tyRef, tyAlias}
@@ -920,7 +914,7 @@ proc readTypeParameter(c: PContext, typ: PType,
 
       else:
         discard
-  
+
   if typ.kind != tyUserTypeClass:
     let ty = if typ.kind == tyCompositeTypeClass: typ.sons[1].skipGenericAlias
              else: typ.skipGenericAlias
@@ -1138,9 +1132,9 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
     # reset to prevent 'nil' bug: see "tests/reject/tenumitems.nim":
     ty = n.sons[0].typ
     return nil
-  ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef, tyAlias})
   if ty.kind in tyUserTypeClasses and ty.isResolvedUserTypeClass:
     ty = ty.lastSon
+  ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef, tyAlias})
   while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct})
   var check: PNode = nil
   if ty.kind == tyObject:
@@ -2156,7 +2150,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     let checks = if efNoEvaluateGeneric in flags: {checkUndeclared}
                  else: {checkUndeclared, checkModule, checkAmbiguity}
     var s = qualifiedLookUp(c, n, checks)
-    if c.inTypeClass == 0: semCaptureSym(s, c.p.owner)
+    if c.matchedConcept == nil: semCaptureSym(s, c.p.owner)
     result = semSym(c, n, s, flags)
     if s.kind in {skProc, skMethod, skConverter, skIterator}:
       #performProcvarCheck(c, n, s)
@@ -2285,14 +2279,14 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
       pragma = n[1]
       pragmaName = considerQuotedIdent(pragma[0])
       flags = flags
-    
+
     case whichKeyword(pragmaName)
     of wExplain:
       flags.incl efExplain
     else:
       # what other pragmas are allowed for expressions? `likely`, `unlikely`
       invalidPragma(n)
-    
+
     result = semExpr(c, n[0], flags)
   of nkPar:
     case checkPar(n)
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 58239d23e..84cb0071f 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -594,8 +594,11 @@ proc foldConStrStr(m: PSym, n: PNode): PNode =
 
 proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode =
   result = newSymNode(s, info)
-  result.typ = newType(tyTypeDesc, s.owner)
-  result.typ.addSonSkipIntLit(s.typ)
+  if s.typ.kind != tyTypeDesc:
+    result.typ = newType(tyTypeDesc, s.owner)
+    result.typ.addSonSkipIntLit(s.typ)
+  else:
+    result.typ = s.typ
 
 proc getConstExpr(m: PSym, n: PNode): PNode =
   result = nil
@@ -634,9 +637,11 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
         result = newSymNodeTypeDesc(s, n.info)
     of skGenericParam:
       if s.typ.kind == tyStatic:
-        if s.typ.n != nil:
+        if s.typ.n != nil and tfUnresolved notin s.typ.flags:
           result = s.typ.n
-          result.typ = s.typ.sons[0]
+          result.typ = s.typ.base
+      elif s.typ.isIntLit:
+        result = s.typ.n
       else:
         result = newSymNodeTypeDesc(s, n.info)
     else: discard
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index 3938259ad..7e55b266a 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -34,7 +34,7 @@ type
 
 type
   TSemGenericFlag = enum
-    withinBind, withinTypeDesc, withinMixin
+    withinBind, withinTypeDesc, withinMixin, withinConcept
   TSemGenericFlags = set[TSemGenericFlag]
 
 proc semGenericStmt(c: PContext, n: PNode,
@@ -200,12 +200,13 @@ proc semGenericStmt(c: PContext, n: PNode,
     checkMinSonsLen(n, 1)
     let fn = n.sons[0]
     var s = qualifiedLookUp(c, fn, {})
-    if s == nil and withinMixin notin flags and
+    if  s == nil and
+        {withinMixin, withinConcept}*flags == {} and
         fn.kind in {nkIdent, nkAccQuoted} and
         considerQuotedIdent(fn).id notin ctx.toMixin:
       errorUndeclaredIdentifier(c, n.info, fn.renderTree)
 
-    var first = 0
+    var first = ord(withinConcept in flags)
     var mixinContext = false
     if s != nil:
       incl(s.flags, sfUsed)
@@ -471,3 +472,9 @@ proc semGenericStmt(c: PContext, n: PNode): PNode =
   ctx.toMixin = initIntset()
   result = semGenericStmt(c, n, {}, ctx)
   semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
+
+proc semConceptBody(c: PContext, n: PNode): PNode =
+  var ctx: GenericCtx
+  ctx.toMixin = initIntset()
+  result = semGenericStmt(c, n, {withinConcept}, ctx)
+  semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index b5dca4c1b..a28d322b1 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -88,7 +88,8 @@ proc sameInstantiation(a, b: TInstantiation): bool =
   if a.concreteTypes.len == b.concreteTypes.len:
     for i in 0..a.concreteTypes.high:
       if not compareTypes(a.concreteTypes[i], b.concreteTypes[i],
-                          flags = {ExactTypeDescValues}): return
+                          flags = {ExactTypeDescValues,
+                                   ExactGcSafety}): return
     result = true
 
 proc genericCacheGet(genericSym: PSym, entry: TInstantiation;
@@ -173,10 +174,14 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
 
 proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
                           allowMetaTypes = false): PType =
-  var cl: TReplTypeVars
+  var
+    typeMap: LayeredIdTable
+    cl: TReplTypeVars
+
   initIdTable(cl.symMap)
-  initIdTable(cl.typeMap)
   initIdTable(cl.localCache)
+  initIdTable(typeMap.topLayer)
+  cl.typeMap = addr(typeMap)
   cl.info = info
   cl.c = c
   cl.allowMetaTypes = allowMetaTypes
@@ -200,7 +205,8 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
   #addDecl(c, prc)
 
   pushInfoContext(info)
-  var cl = initTypeVars(c, pt, info, nil)
+  var typeMap = initLayeredTypeMap(pt)
+  var cl = initTypeVars(c, addr(typeMap), info, nil)
   var result = instCopyType(cl, prc.typ)
   let originalParams = result.n
   result.n = originalParams.shallowCopy
@@ -256,8 +262,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   # NOTE: for access of private fields within generics from a different module
   # we set the friend module:
   c.friendModules.add(getModule(fn))
-  let oldInTypeClass = c.inTypeClass
-  c.inTypeClass = 0
+  let oldMatchedConcept = c.matchedConcept
+  c.matchedConcept = nil
   let oldScope = c.currentScope
   while not isTopLevel(c): c.currentScope = c.currentScope.parent
   result = copySym(fn, false)
@@ -318,5 +324,5 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   c.currentScope = oldScope
   discard c.friendModules.pop()
   dec(c.instCounter)
-  c.inTypeClass = oldInTypeClass
+  c.matchedConcept = oldMatchedConcept
   if result.kind == skMethod: finishMethod(c, result)
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index eb6259df0..c664f735c 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -110,7 +110,7 @@ proc uninstantiate(t: PType): PType =
     else: t
 
 proc evalTypeTrait(traitCall: PNode, operand: PType, context: PSym): PNode =
-  const skippedTypes = {tyTypeDesc}
+  const skippedTypes = {tyTypeDesc, tyAlias}
   let trait = traitCall[0]
   internalAssert trait.kind == nkSym
   var operand = operand.skipTypes(skippedTypes)
@@ -119,7 +119,7 @@ proc evalTypeTrait(traitCall: PNode, operand: PType, context: PSym): PNode =
     traitCall.sons[2].typ.skipTypes({tyTypeDesc})
 
   template typeWithSonsResult(kind, sons): PNode =
-    newTypeWithSons2(kind, context, sons).toNode(traitCall.info)
+    newTypeWithSons(context, kind, sons).toNode(traitCall.info)
 
   case trait.sym.name.s
   of "or", "|":
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index 96bdc6cba..c383f352f 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -218,12 +218,11 @@ proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet) =
       message(s.info, msgKind,
         "'$#' is not GC-safe as it calls '$#'" %
         [s.name.s, u.name.s])
-    of skParam:
+    of skParam, skForVar:
       message(s.info, msgKind,
         "'$#' is not GC-safe as it performs an indirect call via '$#'" %
         [s.name.s, u.name.s])
     else:
-      internalAssert u.kind == skUnknown
       message(u.info, msgKind,
         "'$#' is not GC-safe as it performs an indirect call here" % s.name.s)
 
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 8f522ccc2..ee4203299 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -144,7 +144,7 @@ proc fixNilType(n: PNode) =
   n.typ = nil
 
 proc discardCheck(c: PContext, result: PNode) =
-  if c.inTypeClass > 0: return
+  if c.matchedConcept != nil: return
   if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
     if result.kind == nkNilLit:
       result.typ = nil
@@ -465,6 +465,40 @@ proc hasEmpty(typ: PType): bool =
     for s in typ.sons:
       result = result or hasEmpty(s)
 
+proc makeDeref(n: PNode): PNode =
+  var t = skipTypes(n.typ, {tyGenericInst, tyAlias})
+  if t.kind in tyUserTypeClasses and t.isResolvedUserTypeClass:
+    t = t.lastSon
+  result = n
+  if t.kind == tyVar:
+    result = newNodeIT(nkHiddenDeref, n.info, t.sons[0])
+    addSon(result, n)
+    t = skipTypes(t.sons[0], {tyGenericInst, tyAlias})
+  while t.kind in {tyPtr, tyRef}:
+    var a = result
+    let baseTyp = t.lastSon
+    result = newNodeIT(nkHiddenDeref, n.info, baseTyp)
+    addSon(result, a)
+    t = skipTypes(baseTyp, {tyGenericInst, tyAlias})
+
+proc fillPartialObject(c: PContext; n: PNode; typ: PType) =
+  if n.len == 2:
+    let x = semExprWithType(c, n[0])
+    let y = considerQuotedIdent(n[1])
+    let obj = x.typ.skipTypes(abstractPtrs)
+    if obj.kind == tyObject and tfPartial in obj.flags:
+      let field = newSym(skField, getIdent(y.s), obj.sym, n[1].info)
+      field.typ = skipIntLit(typ)
+      field.position = sonsLen(obj.n)
+      addSon(obj.n, newSymNode(field))
+      n.sons[0] = makeDeref x
+      n.sons[1] = newSymNode(field)
+    else:
+      localError(n.info, "implicit object field construction " &
+        "requires a .partial object, but got " & typeToString(obj))
+  else:
+    localError(n.info, "nkDotNode requires 2 children")
+
 proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
   var b: PNode
   result = copyNode(n)
@@ -529,6 +563,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
       message(a.info, warnEachIdentIsTuple)
 
     for j in countup(0, length-3):
+      if a[j].kind == nkDotExpr:
+        fillPartialObject(c, a[j],
+          if a.kind != nkVarTuple: typ else: tup.sons[j])
+        addToVarSection(c, result, n, a)
+        continue
       var v = semIdentDef(c, a.sons[j], symkind)
       if sfGenSym notin v.flags and not isDiscardUnderscore(v):
         addInterfaceDecl(c, v)
@@ -1092,7 +1131,7 @@ proc semProcAnnotation(c: PContext, prc: PNode;
       x.add(it.sons[1])
     x.add(prc)
     # recursion assures that this works for multiple macro annotations too:
-    result = semStmt(c, x)
+    result = semExpr(c, x)
     # since a proc annotation can set pragmas, we process these here again.
     # This is required for SqueakNim-like export pragmas.
     if result.kind in procDefs and result[namePos].kind == nkSym and
@@ -1724,7 +1763,8 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
     else:
       var expr = semExpr(c, n.sons[i], flags)
       n.sons[i] = expr
-      if c.inTypeClass > 0 and expr.typ != nil:
+      if c.matchedConcept != nil and expr.typ != nil and
+         (nfFromTemplate notin n.flags or i != last):
         case expr.typ.kind
         of tyBool:
           if expr.kind == nkInfix and
@@ -1739,7 +1779,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
 
           let verdict = semConstExpr(c, n[i])
           if verdict.intVal == 0:
-            localError(result.info, "type class predicate failed")
+            localError(result.info, "concept predicate failed")
         of tyUnknown: continue
         else: discard
       if n.sons[i].typ == enforceVoidContext: #or usesResult(n.sons[i]):
@@ -1763,7 +1803,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
 
   if result.len == 1 and
      # concept bodies should be preserved as a stmt list:
-     c.inTypeClass == 0 and
+     c.matchedConcept == nil and
      # also, don't make life complicated for macros.
      # they will always expect a proper stmtlist:
      nfBlockArg notin n.flags and
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 09f90d8d0..0c2dd2f96 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -152,6 +152,8 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
           message n[i].info, errGenerated, "region needs to be an object type"
         addSonSkipIntLit(result, region)
     addSonSkipIntLit(result, t)
+    if tfPartial in result.flags:
+      if result.lastSon.kind == tyObject: incl(result.lastSon.flags, tfPartial)
     #if not isNilable: result.flags.incl tfNotNil
 
 proc semVarType(c: PContext, n: PNode, prev: PType): PType =
@@ -1129,7 +1131,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
     m.isNoCall = true
     matches(c, n, copyTree(n), m)
 
-    if m.state != csMatch and not m.typedescMatched:
+    if m.state != csMatch:
       let err = "cannot instantiate " & typeToString(t) & "\n" &
                 "got: (" & describeArgs(c, n) & ")\n" &
                 "but expected: (" & describeArgs(c, t.n, 0) & ")"
@@ -1200,17 +1202,51 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
   # if n.sonsLen == 0: return newConstraint(c, tyTypeClass)
   if nfBase2 in n.flags:
     message(n.info, warnDeprecated, "use 'concept' instead; 'generic'")
-  result = newOrPrevType(tyUserTypeClass, prev, c)
-  result.n = n
-
   let
     pragmas = n[1]
     inherited = n[2]
 
+  result = newOrPrevType(tyUserTypeClass, prev, c)
+  var owner = getCurrOwner(c)
+  var candidateTypeSlot = newTypeWithSons(owner, tyAlias, @[c.errorType])
+  result.sons = @[candidateTypeSlot]
+  result.n = n
+
   if inherited.kind != nkEmpty:
     for n in inherited.sons:
       let typ = semTypeNode(c, n, nil)
-      result.sons.safeAdd(typ)
+      result.sons.add(typ)
+
+  openScope(c)
+  for param in n[0]:
+    var
+      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
+
+    if modifier != tyNone:
+      dummyName = param[0]
+      dummyType = c.makeTypeWithModifier(modifier, candidateTypeSlot)
+      if modifier == tyTypeDesc: dummyType.flags.incl tfExplicit
+    else:
+      dummyName = param
+      dummyType = candidateTypeSlot
+
+    internalAssert dummyName.kind == nkIdent
+    var dummyParam = newSym(if modifier == tyTypeDesc: skType else: skVar,
+                            dummyName.ident, owner, owner.info)
+    dummyParam.typ = dummyType
+    addDecl(c, dummyParam)
+
+  result.n.sons[3] = semConceptBody(c, n[3])
+  closeScope(c)
 
 proc semProcTypeWithScope(c: PContext, n: PNode,
                         prev: PType, kind: TSymKind): PType =
@@ -1379,7 +1415,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
       result = errorType(c)
     else:
       result = typeExpr.typ.base
-      if result.isMetaType:
+      if result.isMetaType and
+         result.kind != tyUserTypeClass:
+           # the dot expression may refer to a concept type in
+           # a different module. allow a normal alias then.
         let preprocessed = semGenericStmt(c, n)
         result = makeTypeFromExpr(c, preprocessed.copyTree)
       else:
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 80fb9168b..b4a61deb7 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -73,9 +73,13 @@ proc cacheTypeInst*(inst: PType) =
 
 
 type
+  LayeredIdTable* = object
+    topLayer*: TIdTable
+    nextLayer*: ptr LayeredIdTable
+
   TReplTypeVars* {.final.} = object
     c*: PContext
-    typeMap*: TIdTable        # map PType to PType
+    typeMap*: ptr LayeredIdTable # map PType to PType
     symMap*: TIdTable         # map PSym to PSym
     localCache*: TIdTable     # local cache for remembering alraedy replaced
                               # types during instantiation of meta types
@@ -91,6 +95,23 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType
 proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
 proc replaceTypeVarsN*(cl: var TReplTypeVars, n: PNode; start=0): PNode
 
+proc initLayeredTypeMap*(pt: TIdTable): LayeredIdTable =
+  copyIdTable(result.topLayer, pt)
+
+proc newTypeMapLayer*(cl: var TReplTypeVars): LayeredIdTable =
+  result.nextLayer = cl.typeMap
+  initIdTable(result.topLayer)
+
+proc lookup(typeMap: ptr LayeredIdTable, key: PType): PType =
+  var tm = typeMap
+  while tm != nil:
+    result = PType(idTableGet(tm.topLayer, key))
+    if result != nil: return
+    tm = tm.nextLayer
+
+template put(typeMap: ptr LayeredIdTable, key, value: PType) =
+  idTablePut(typeMap.topLayer, key, value)
+
 template checkMetaInvariants(cl: TReplTypeVars, t: PType) =
   when false:
     if t != nil and tfHasMeta in t.flags and
@@ -106,7 +127,8 @@ proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
 proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
   let t = replaceTypeVarsT(cl, n.typ)
   if t != nil and t.kind == tyStatic and t.n != nil:
-    return t.n
+    return if tfUnresolved in t.flags: prepareNode(cl, t.n)
+           else: t.n
   result = copyNode(n)
   result.typ = t
   if result.kind == nkSym: result.sym = replaceTypeVarsS(cl, n.sym)
@@ -219,7 +241,7 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
   result.ast = replaceTypeVarsN(cl, s.ast)
 
 proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
-  result = PType(idTableGet(cl.typeMap, t))
+  result = cl.typeMap.lookup(t)
   if result == nil:
     if cl.allowMetaTypes or tfRetType in t.flags: return
     localError(t.sym.info, errCannotInstantiateX, typeToString(t))
@@ -227,7 +249,7 @@ proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
     # In order to prevent endless recursions, we must remember
     # this bad lookup and replace it with errorType everywhere.
     # These code paths are only active in "nim check"
-    idTablePut(cl.typeMap, t, result)
+    cl.typeMap.put(t, result)
   elif result.kind == tyGenericParam and not cl.allowMetaTypes:
     internalError(cl.info, "substitution with generic parameter")
 
@@ -243,6 +265,7 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
 proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
   # tyGenericInvocation[A, tyGenericInvocation[A, B]]
   # is difficult to handle:
+  const eqFlags = eqTypeFlags + {tfGcSafe}
   var body = t.sons[0]
   if body.kind != tyGenericBody: internalError(cl.info, "no generic body")
   var header: PType = t
@@ -252,7 +275,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
   else:
     result = searchInstTypes(t)
 
-  if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return
+  if result != nil and eqFlags*result.flags == eqFlags*t.flags: return
   for i in countup(1, sonsLen(t) - 1):
     var x = t.sons[i]
     if x.kind in {tyGenericParam}:
@@ -267,7 +290,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
   if header != t:
     # search again after first pass:
     result = searchInstTypes(header)
-    if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return
+    if result != nil and eqFlags*result.flags == eqFlags*t.flags: return
   else:
     header = instCopyType(cl, t)
 
@@ -285,12 +308,16 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
 
   let oldSkipTypedesc = cl.skipTypedesc
   cl.skipTypedesc = true
+
+  var typeMapLayer = newTypeMapLayer(cl)
+  cl.typeMap = addr(typeMapLayer)
+
   for i in countup(1, sonsLen(t) - 1):
     var x = replaceTypeVarsT(cl, t.sons[i])
     assert x.kind != tyGenericInvocation
     header.sons[i] = x
     propagateToOwner(header, x)
-    idTablePut(cl.typeMap, body.sons[i-1], x)
+    cl.typeMap.put(body.sons[i-1], x)
 
   for i in countup(1, sonsLen(t) - 1):
     # if one of the params is not concrete, we cannot do anything
@@ -303,6 +330,9 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
   cl.skipTypedesc = oldSkipTypedesc
   newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
   result.flags = result.flags + newbody.flags - tfInstClearedFlags
+
+  cl.typeMap = cl.typeMap.nextLayer
+
   # This is actually wrong: tgeneric_closure fails with this line:
   #newbody.callConv = body.callConv
   # This type may be a generic alias and we want to resolve it here.
@@ -404,7 +434,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
   if t == nil: return
 
   if t.kind in {tyStatic, tyGenericParam} + tyTypeClasses:
-    let lookup = PType(idTableGet(cl.typeMap, t))
+    let lookup = cl.typeMap.lookup(t)
     if lookup != nil: return lookup
 
   case t.kind
@@ -446,7 +476,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
     result = skipIntLit(t)
 
   of tyTypeDesc:
-    let lookup = PType(idTableGet(cl.typeMap, t)) # lookupTypeVar(cl, t)
+    let lookup = cl.typeMap.lookup(t)
     if lookup != nil:
       result = lookup
       if tfUnresolved in t.flags or cl.skipTypedesc: result = result.base
@@ -485,7 +515,6 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
           propagateToOwner(result, r)
       # bug #4677: Do not instantiate effect lists
       result.n = replaceTypeVarsN(cl, result.n, ord(result.kind==tyProc))
-
       case result.kind
       of tyArray:
         let idx = result.sons[0]
@@ -500,18 +529,19 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
 
       else: discard
 
-proc initTypeVars*(p: PContext, pt: TIdTable, info: TLineInfo;
+proc initTypeVars*(p: PContext, typeMap: ptr LayeredIdTable, info: TLineInfo;
                    owner: PSym): TReplTypeVars =
   initIdTable(result.symMap)
-  copyIdTable(result.typeMap, pt)
   initIdTable(result.localCache)
+  result.typeMap = typeMap
   result.info = info
   result.c = p
   result.owner = owner
 
 proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode;
                          owner: PSym, allowMetaTypes = false): PNode =
-  var cl = initTypeVars(p, pt, n.info, owner)
+  var typeMap = initLayeredTypeMap(pt)
+  var cl = initTypeVars(p, addr(typeMap), n.info, owner)
   cl.allowMetaTypes = allowMetaTypes
   pushInfoContext(n.info)
   result = replaceTypeVarsN(cl, n)
@@ -519,7 +549,8 @@ proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode;
 
 proc replaceTypesForLambda*(p: PContext, pt: TIdTable, n: PNode;
                             original, new: PSym): PNode =
-  var cl = initTypeVars(p, pt, n.info, original)
+  var typeMap = initLayeredTypeMap(pt)
+  var cl = initTypeVars(p, addr(typeMap), n.info, original)
   idTablePut(cl.symMap, original, new)
   pushInfoContext(n.info)
   result = replaceTypeVarsN(cl, n)
@@ -527,14 +558,16 @@ proc replaceTypesForLambda*(p: PContext, pt: TIdTable, n: PNode;
 
 proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
                            t: PType): PType =
-  var cl = initTypeVars(p, pt, info, nil)
+  var typeMap = initLayeredTypeMap(pt)
+  var cl = initTypeVars(p, addr(typeMap), info, nil)
   pushInfoContext(info)
   result = replaceTypeVarsT(cl, t)
   popInfoContext()
 
 proc prepareMetatypeForSigmatch*(p: PContext, pt: TIdTable, info: TLineInfo,
                                  t: PType): PType =
-  var cl = initTypeVars(p, pt, info, nil)
+  var typeMap = initLayeredTypeMap(pt)
+  var cl = initTypeVars(p, addr(typeMap), info, nil)
   cl.allowMetaTypes = true
   pushInfoContext(info)
   result = replaceTypeVarsT(cl, t)
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index cb526947e..6084e11c0 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -204,7 +204,9 @@ proc sumGeneric(t: PType): int =
         if t.sons[i] != nil:
           result += t.sons[i].sumGeneric
       break
-    of tyGenericParam, tyExpr, tyStatic, tyStmt: break
+    of tyStatic:
+      return t.sons[0].sumGeneric + 1
+    of tyGenericParam, tyExpr, tyStmt: break
     of tyAlias: t = t.lastSon
     of tyBool, tyChar, tyEnum, tyObject, tyPointer,
         tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
@@ -302,8 +304,32 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
     add(result, argTypeToString(arg, prefer))
     if i != sonsLen(n) - 1: add(result, ", ")
 
-proc typeRel*(c: var TCandidate, f, aOrig: PType,
-              flags: TTypeRelFlags = {}): TTypeRelation
+proc typeRelImpl*(c: var TCandidate, f, aOrig: PType,
+                  flags: TTypeRelFlags = {}): TTypeRelation
+
+const traceTypeRel = false
+
+when traceTypeRel:
+  var nextTypeRel = 0
+
+template typeRel*(c: var TCandidate, f, aOrig: PType,
+                 flags: TTypeRelFlags = {}): TTypeRelation =
+  when traceTypeRel:
+    var enteringAt = nextTypeRel
+    if mdbg:
+      inc nextTypeRel
+      echo "----- TYPE REL ", enteringAt
+      debug f
+      debug aOrig
+      # writeStackTrace()
+
+  let r = typeRelImpl(c, f, aOrig, flags)
+
+  when traceTypeRel:
+    if enteringAt != nextTypeRel:
+      echo "----- TYPE REL ", enteringAt, " RESULT: ", r
+
+  r
 
 proc concreteType(c: TCandidate, t: PType): PType =
   case t.kind
@@ -602,19 +628,29 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
   else:
     result = isNone
 
-proc matchUserTypeClass*(c: PContext, m: var TCandidate,
-                         ff, a: PType): PType =
+proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
   var
+    c = m.c
     typeClass = ff.skipTypes({tyUserTypeClassInst})
     body = typeClass.n[3]
-  if c.inTypeClass > 4:
-    localError(body.info, $body & " too nested for type matching")
-    return nil
+    matchedConceptContext: TMatchedConcept
+    prevMatchedConcept = c.matchedConcept
+    prevCandidateType = typeClass[0][0]
+
+  if prevMatchedConcept != nil:
+    matchedConceptContext.prev = prevMatchedConcept
+    matchedConceptContext.depth = prevMatchedConcept.depth + 1
+    if prevMatchedConcept.depth > 4:
+      localError(body.info, $body & " too nested for type matching")
+      return nil
 
   openScope(c)
-  inc c.inTypeClass
+  matchedConceptContext.candidateType = a
+  typeClass[0].sons[0] = a
+  c.matchedConcept = addr(matchedConceptContext)
   defer:
-    dec c.inTypeClass
+    c.matchedConcept = prevMatchedConcept
+    typeClass[0].sons[0] = prevCandidateType
     closeScope(c)
 
   var typeParams: seq[(PSym, PType)]
@@ -625,6 +661,9 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
         typeParamName = ff.base.sons[i-1].sym.name
         typ = ff.sons[i]
         param: PSym
+        alreadyBound = PType(idTableGet(m.bindings, typ))
+
+      if alreadyBound != nil: typ = alreadyBound
 
       template paramSym(kind): untyped =
         newSym(kind, typeParamName, typeClass.sym, typeClass.sym.info)
@@ -658,33 +697,6 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
 
       addDecl(c, param)
 
-  for param in typeClass.n[0]:
-    var
-      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
-
-    if modifier != tyNone:
-      dummyName = param[0]
-      dummyType = c.makeTypeWithModifier(modifier, a)
-      if modifier == tyTypeDesc: dummyType.flags.incl tfExplicit
-    else:
-      dummyName = param
-      dummyType = a
-
-    internalAssert dummyName.kind == nkIdent
-    var dummyParam = newSym(if modifier == tyTypeDesc: skType else: skVar,
-                            dummyName.ident, typeClass.sym, typeClass.sym.info)
-    dummyParam.typ = dummyType
-    addDecl(c, dummyParam)
-
   var
     oldWriteHook: type(writelnHook)
     diagnostics: seq[string]
@@ -826,7 +838,7 @@ proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool =
     var inferred = newTypeWithSons(c.c, tyStatic, lhs.typ.sons)
     inferred.n = newIntNode(nkIntLit, rhs)
     put(c, lhs.typ, inferred)
-    if c.c.inTypeClass > 0:
+    if c.c.matchedConcept != nil:
       # inside concepts, binding is currently done with
       # direct mutation of the involved types:
       lhs.typ.n = inferred.n
@@ -888,8 +900,8 @@ proc isCovariantPtr(c: var TCandidate, f, a: PType): bool =
   else:
     return false
 
-proc typeRel(c: var TCandidate, f, aOrig: PType,
-             flags: TTypeRelFlags = {}): TTypeRelation =
+proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
+                 flags: TTypeRelFlags = {}): TTypeRelation =
   # typeRel can be used to establish various relationships between types:
   #
   # 1) When used with concrete types, it will check for type equivalence
@@ -916,7 +928,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
   assert(aOrig != nil)
 
   var
-    useTypeLoweringRuleInTypeClass = c.c.inTypeClass > 0 and
+    useTypeLoweringRuleInTypeClass = c.c.matchedConcept != nil and
                                      not c.isNoCall and
                                      f.kind != tyTypeDesc and
                                      tfExplicit notin aOrig.flags
@@ -965,7 +977,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
   # for example, but unfortunately `prepareOperand` is not called in certain
   # situation when nkDotExpr are rotated to nkDotCalls
 
-  if a.kind in {tyGenericInst, tyAlias} and
+  if aOrig.kind == tyAlias:
+    return typeRel(c, f, lastSon(aOrig))
+
+  if a.kind == tyGenericInst and
       skipTypes(f, {tyVar}).kind notin {
         tyGenericBody, tyGenericInvocation,
         tyGenericInst, tyGenericParam} + tyTypeClasses:
@@ -1030,11 +1045,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
            else: isNone
 
   of tyUserTypeClass, tyUserTypeClassInst:
-    # consider this: 'var g: Node' *within* a concept where 'Node'
-    # is a concept too (tgraph)
-    let x = typeRel(c, a, f, flags + {trDontBind})
-    if x >= isGeneric:
-      return isGeneric
+    if c.c.matchedConcept != nil:
+      # consider this: 'var g: Node' *within* a concept where 'Node'
+      # is a concept too (tgraph)
+      let x = typeRel(c, a, f, flags + {trDontBind})
+      if x >= isGeneric:
+        return isGeneric
   else: discard
 
   case f.kind
@@ -1106,7 +1122,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
 
       if fRange.rangeHasUnresolvedStatic:
         return inferStaticsInRange(c, fRange, a)
-      elif c.c.inTypeClass > 0 and aRange.rangeHasUnresolvedStatic:
+      elif c.c.matchedConcept != nil and aRange.rangeHasUnresolvedStatic:
         return inferStaticsInRange(c, aRange, f)
       else:
         if lengthOrd(fRange) != lengthOrd(aRange):
@@ -1339,7 +1355,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
         result = isNone
     else:
       result = typeRel(c, lastSon(f), a)
-      if result != isNone: put(c, f, a)
+      if result != isNone and a.kind != tyNil:
+        put(c, f, a)
 
   of tyGenericBody:
     considerPreviousT:
@@ -1475,7 +1492,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
       result = typeRel(c, f.lastSon, a)
     else:
       considerPreviousT:
-        var matched = matchUserTypeClass(c.c, c, f, aOrig)
+        if aOrig == f: return isEqual
+        var matched = matchUserTypeClass(c, f, aOrig)
         if matched != nil:
           bindConcreteTypeToUserTypeClass(matched, a)
           if doBind: put(c, f, matched)
@@ -1567,6 +1585,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
           if not exprStructuralEquivalent(f.n, aOrig.n):
             result = isNone
         if result != isNone: put(c, f, aOrig)
+      elif aOrig.n != nil:
+        result = typeRel(c, f.lastSon, aOrig.n.typ)
+        if result != isNone:
+          var boundType = newTypeWithSons(c.c, tyStatic, @[aOrig.n.typ])
+          boundType.n = aOrig.n
+          put(c, f, boundType)
       else:
         result = isNone
     elif prev.kind == tyStatic:
@@ -1770,6 +1794,13 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
         arg.typ.sons = @[evaluated.typ]
         arg.typ.n = evaluated
         a = arg.typ
+      else:
+        if m.callee.kind == tyGenericBody:
+          if f.kind == tyStatic and typeRel(m, f.base, a) != isNone:
+            result = makeStaticExpr(m.c, arg)
+            result.typ.flags.incl tfUnresolved
+            result.typ.n = arg
+            return
 
   var r = typeRel(m, f, a)
 
@@ -2219,6 +2250,8 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
         var def = copyTree(formal.ast)
         if def.kind == nkNilLit:
           def = implicitConv(nkHiddenStdConv, formal.typ, def, m, c)
+        if {tfImplicitTypeParam, tfGenericTypeParam} * formal.typ.flags != {}:
+          put(m, formal.typ, def.typ)
         setSon(m.call, formal.position + 1, def)
     inc(f)
   # forget all inferred types if the overload matching failed
diff --git a/compiler/trees.nim b/compiler/trees.nim
index 8f0af89d3..c77dab349 100644
--- a/compiler/trees.nim
+++ b/compiler/trees.nim
@@ -41,6 +41,7 @@ proc exprStructuralEquivalent*(a, b: PNode; strictSymEquality=false): bool =
     of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal
     of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
     of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
+    of nkCommentStmt: result = a.comment == b.comment
     of nkEmpty, nkNilLit, nkType: result = true
     else:
       if sonsLen(a) == sonsLen(b):
@@ -109,9 +110,11 @@ proc isDeepConstExpr*(n: PNode): bool =
 
 proc isRange*(n: PNode): bool {.inline.} =
   if n.kind in nkCallKinds:
-    if n[0].kind == nkIdent and n[0].ident.id == ord(wDotDot) or
-        n[0].kind in {nkClosedSymChoice, nkOpenSymChoice} and
-        n[0][1].sym.name.id == ord(wDotDot):
+    let callee = n[0]
+    if (callee.kind == nkIdent and callee.ident.id == ord(wDotDot)) or
+       (callee.kind == nkSym and callee.sym.name.id == ord(wDotDot)) or
+       (callee.kind in {nkClosedSymChoice, nkOpenSymChoice} and
+        callee[1].sym.name.id == ord(wDotDot)):
       result = true
 
 proc whichPragma*(n: PNode): TSpecialWord =
diff --git a/compiler/types.nim b/compiler/types.nim
index 2886ac619..dc7cd52db 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -139,6 +139,9 @@ proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string =
   add(result, ')')
   if n.sons[0].typ != nil:
     result.add(": " & typeToString(n.sons[0].typ, prefer))
+  result.add "[declared in "
+  result.add($sym.info)
+  result.add "]"
 
 proc elemType*(t: PType): PType =
   assert(t != nil)
@@ -421,6 +424,12 @@ template bindConcreteTypeToUserTypeClass*(tc, concrete: PType) =
   tc.sons.safeAdd concrete
   tc.flags.incl tfResolved
 
+# TODO: It would be a good idea to kill the special state of a resolved
+# concept by switching to tyAlias within the instantiated procs.
+# Currently, tyAlias is always skipped with lastSon, which means that
+# we can store information about the matched concept in another position.
+# Then builtInFieldAccess can be modified to properly read the derived
+# consts and types stored within the concept.
 template isResolvedUserTypeClass*(t: PType): bool =
   tfResolved in t.flags
 
@@ -437,6 +446,13 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
       result = t.sym.name.s & " literal(" & $t.n.intVal & ")"
     elif prefer == preferName or t.sym.owner.isNil:
       result = t.sym.name.s
+      if t.kind == tyGenericParam and t.sons != nil and t.sonsLen > 0:
+        result.add ": "
+        var first = true
+        for son in t.sons:
+          if not first: result.add " or "
+          result.add son.typeToString
+          first = false
     else:
       result = t.sym.owner.name.s & '.' & t.sym.name.s
     result.addTypeFlags(t)
@@ -458,7 +474,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
     add(result, ']')
   of tyTypeDesc:
     if t.sons[0].kind == tyNone: result = "typedesc"
-    else: result = "typedesc[" & typeToString(t.sons[0]) & "]"
+    else: result = "type " & typeToString(t.sons[0])
   of tyStatic:
     internalAssert t.len > 0
     if prefer == preferGenericArg and t.n != nil:
@@ -688,6 +704,7 @@ type
     ExactTypeDescValues
     ExactGenericParams
     ExactConstraints
+    ExactGcSafety
     AllowCommonBase
 
   TTypeCmpFlags* = set[TTypeCmpFlag]
@@ -976,6 +993,8 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
     cycleCheck()
     if a.kind == tyUserTypeClass and a.n != nil: return a.n == b.n
     result = sameChildrenAux(a, b, c) and sameFlags(a, b)
+    if result and ExactGcSafety in c.flags:
+      result = a.flags * {tfThread} == b.flags * {tfThread}
     if result and a.kind == tyProc:
       result = ((IgnoreCC in c.flags) or a.callConv == b.callConv) and
                ((ExactConstraints notin c.flags) or sameConstraints(a.n, b.n))
diff --git a/compiler/vm.nim b/compiler/vm.nim
index e201e98dc..b8e6467b5 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -1406,6 +1406,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       if dest.kind in {nkStrLit..nkTripleStrLit} and
          regs[rb].kind in {rkNode}:
         dest.strVal = regs[rb].node.strVal
+      elif dest.kind == nkCommentStmt and regs[rb].kind in {rkNode}:
+        dest.comment = regs[rb].node.strVal
       else:
         stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
     of opcNNewNimNode:
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index c7d9be48c..ba89f88d4 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -826,7 +826,23 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mSubF64: genBinaryABC(c, n, dest, opcSubFloat)
   of mMulF64: genBinaryABC(c, n, dest, opcMulFloat)
   of mDivF64: genBinaryABC(c, n, dest, opcDivFloat)
-  of mShrI: genBinaryABCnarrowU(c, n, dest, opcShrInt)
+  of mShrI:
+    # the idea here is to narrow type if needed before executing right shift
+    # inlined modified: genNarrowU(c, n, dest)
+    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:
+    let tmp = c.genx(n.sons[1])
+    if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32}:
+      c.gABC(n, opcNarrowU, tmp, TRegister(t.size*8))
+
+    # inlined modified: genBinaryABC(c, n, dest, opcShrInt)
+    let tmp2 = c.genx(n.sons[2])
+    if dest < 0: dest = c.getTemp(n.typ)
+    c.gABC(n, opcShrInt, dest, tmp, tmp2)
+    c.freeTemp(tmp)
+    c.freeTemp(tmp2)
+
   of mShlI: genBinaryABCnarrowU(c, n, dest, opcShlInt)
   of mBitandI: genBinaryABCnarrowU(c, n, dest, opcBitandInt)
   of mBitorI: genBinaryABCnarrowU(c, n, dest, opcBitorInt)
diff --git a/doc/astspec.txt b/doc/astspec.txt
index f430677af..57f6b9d8c 100644
--- a/doc/astspec.txt
+++ b/doc/astspec.txt
@@ -461,8 +461,8 @@ Documentation Comments
 ----------------------
 
 Double-hash (``##``) comments in the code actually have their own format,
-but the comments do not yet show up in the AST, which will only show that
-a comment exists, not what it contains. Single-hash (``#``) comments are ignored.
+using ``strVal`` to get and set the comment text. Single-hash (``#``) 
+comments are ignored.
 
 Concrete syntax:
 
diff --git a/doc/nims.rst b/doc/nims.rst
index 967dd4149..d4ef0055f 100644
--- a/doc/nims.rst
+++ b/doc/nims.rst
@@ -108,3 +108,12 @@ installation of Nimble is done with this simple script:
 
   mvFile "nimble" & $id & "/src/nimble".toExe, "bin/nimble".toExe
 
+You can also use the shebang ``#!/usr/bin/env nim``, as long as your filename
+ends with ``.nims``:
+
+.. code-block:: nim
+
+  #!/usr/bin/env nim
+  mode = ScriptMode.Silent
+
+  echo "hello world"
diff --git a/koch.nim b/koch.nim
index 0fa06f273..aaa03d558 100644
--- a/koch.nim
+++ b/koch.nim
@@ -152,6 +152,10 @@ proc tryExec(cmd: string): bool =
 proc safeRemove(filename: string) =
   if existsFile(filename): removeFile(filename)
 
+proc overwriteFile(source, dest: string) =
+  safeRemove(dest)
+  moveFile(source, dest)
+
 proc copyExe(source, dest: string) =
   safeRemove(dest)
   copyFile(dest=dest, source=source)
@@ -388,33 +392,17 @@ proc clean(args: string) =
 
 # -------------- builds a release ---------------------------------------------
 
-proc patchConfig(lookFor, replaceBy: string) =
-  const
-    cfgFile = "config/nim.cfg"
-  try:
-    let cfg = readFile(cfgFile)
-    let newCfg = cfg.replace(lookFor, replaceBy)
-    if newCfg == cfg:
-      echo "Could not patch 'config/nim.cfg' [Error]"
-      echo "Reason: patch substring not found:"
-      echo lookFor
-    else:
-      writeFile(cfgFile, newCfg)
-  except IOError:
-    quit "Could not access 'config/nim.cfg' [Error]"
-
 proc winReleaseArch(arch: string) =
   doAssert arch in ["32", "64"]
   let cpu = if arch == "32": "i386" else: "amd64"
 
   template withMingw(path, body) =
-    const orig = """#gcc.path = r"$nim\dist\mingw\bin""""
-    let replacePattern = """gcc.path = r"..\mingw$1\bin" # winrelease""" % arch
-    patchConfig(orig, replacePattern)
+    let prevPath = getEnv("PATH")
+    putEnv("PATH", path & PathSep & prevPath)
     try:
       body
     finally:
-      patchConfig(replacePattern, orig)
+      putEnv("PATH", prevPath)
 
   withMingw r"..\mingw" & arch & r"\bin":
     # Rebuilding koch is necessary because it uses its pointer size to
@@ -422,7 +410,7 @@ proc winReleaseArch(arch: string) =
     nimexec "c --out:koch_temp --cpu:$# koch" % cpu
     exec "koch_temp boot -d:release --cpu:$#" % cpu
     exec "koch_temp zip -d:release"
-    moveFile r"build\nim-$#.zip" % VersionAsString,
+    overwriteFile r"build\nim-$#.zip" % VersionAsString,
              r"web\upload\download\nim-$#_x$#.zip" % [VersionAsString, arch]
 
 proc winRelease() =
@@ -431,8 +419,8 @@ proc winRelease() =
     web(gaCode)
     withDir "web/upload/" & VersionAsString:
       exec "7z a -tzip docs-$#.zip *.html" % VersionAsString
-    moveFile "web/upload/$1/docs-$1.zip" % VersionAsString,
-             "web/upload/download/docs-$1.zip" % VersionAsString
+    overwriteFile "web/upload/$1/docs-$1.zip" % VersionAsString,
+                  "web/upload/download/docs-$1.zip" % VersionAsString
   when true:
     csource("-d:release")
   when true:
@@ -482,6 +470,17 @@ proc temp(args: string) =
   copyExe(output, finalDest)
   if programArgs.len > 0: exec(finalDest & " " & programArgs)
 
+proc xtemp(cmd: string) =
+  let d = getAppDir()
+  copyExe(d / "bin" / "nim".exe, d / "bin" / "nim_backup".exe)
+  try:
+    withDir(d):
+      temp"-d:debug"
+    copyExe(d / "bin" / "nim_temp".exe, d / "bin" / "nim".exe)
+    exec(cmd)
+  finally:
+    copyExe(d / "bin" / "nim_backup".exe, d / "bin" / "nim".exe)
+
 proc pushCsources() =
   if not dirExists("../csources/.git"):
     quit "[Error] no csources git repository found"
@@ -557,6 +556,7 @@ of cmdArgument:
   of "testinstall": testUnixInstall()
   of "test", "tests": tests(op.cmdLineRest)
   of "temp": temp(op.cmdLineRest)
+  of "xtemp": xtemp(op.cmdLineRest)
   of "winrelease": winRelease()
   of "wintools": bundleWinTools()
   of "nimble": buildNimble(existsDir(".git"))
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 03ac09180..af1e9de28 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -255,6 +255,11 @@ proc newStrLitNode*(s: string): NimNode {.compileTime, noSideEffect.} =
   result = newNimNode(nnkStrLit)
   result.strVal = s
 
+proc newCommentStmtNode*(s: string): NimNode {.compileTime, noSideEffect.} =
+  ## creates a comment statement node
+  result = newNimNode(nnkCommentStmt)
+  result.strVal = s
+
 proc newIntLitNode*(i: BiggestInt): NimNode {.compileTime.} =
   ## creates a int literal node from `i`
   result = newNimNode(nnkIntLit)
@@ -275,6 +280,7 @@ proc newIdentNode*(i: string): NimNode {.compileTime.} =
   result = newNimNode(nnkIdent)
   result.ident = !i
 
+
 type
   BindSymRule* = enum    ## specifies how ``bindSym`` behaves
     brClosed,            ## only the symbols in current scope are bound
@@ -432,20 +438,105 @@ proc newLit*(c: char): NimNode {.compileTime.} =
   result = newNimNode(nnkCharLit)
   result.intVal = ord(c)
 
-proc newLit*(i: BiggestInt): NimNode {.compileTime.} =
+
+proc newLit*(i: int): NimNode {.compileTime.} =
   ## produces a new integer literal node.
   result = newNimNode(nnkIntLit)
   result.intVal = i
 
+proc newLit*(i: int8): NimNode {.compileTime.} =
+  ## produces a new integer literal node.
+  result = newNimNode(nnkInt8Lit)
+  result.intVal = i
+
+proc newLit*(i: int16): NimNode {.compileTime.} =
+  ## produces a new integer literal node.
+  result = newNimNode(nnkInt16Lit)
+  result.intVal = i
+
+proc newLit*(i: int32): NimNode {.compileTime.} =
+  ## produces a new integer literal node.
+  result = newNimNode(nnkInt32Lit)
+  result.intVal = i
+
+proc newLit*(i: int64): NimNode {.compileTime.} =
+  ## produces a new integer literal node.
+  result = newNimNode(nnkInt64Lit)
+  result.intVal = i
+
+proc newLit*(i: uint): NimNode {.compileTime.} =
+  ## produces a new unsigned integer literal node.
+  result = newNimNode(nnkUIntLit)
+  result.intVal = BiggestInt(i)
+
+proc newLit*(i: uint8): NimNode {.compileTime.} =
+  ## produces a new unsigned integer literal node.
+  result = newNimNode(nnkUInt8Lit)
+  result.intVal = BiggestInt(i)
+
+proc newLit*(i: uint16): NimNode {.compileTime.} =
+  ## produces a new unsigned integer literal node.
+  result = newNimNode(nnkUInt16Lit)
+  result.intVal = BiggestInt(i)
+
+proc newLit*(i: uint32): NimNode {.compileTime.} =
+  ## produces a new unsigned integer literal node.
+  result = newNimNode(nnkUInt32Lit)
+  result.intVal = BiggestInt(i)
+
+proc newLit*(i: uint64): NimNode {.compileTime.} =
+  ## produces a new unsigned integer literal node.
+  result = newNimNode(nnkUInt64Lit)
+  result.intVal = BiggestInt(i)
+
 proc newLit*(b: bool): NimNode {.compileTime.} =
   ## produces a new boolean literal node.
   result = if b: bindSym"true" else: bindSym"false"
 
-proc newLit*(f: BiggestFloat): NimNode {.compileTime.} =
+when false:
+  # the float type is not really a distinct type as described in https://github.com/nim-lang/Nim/issues/5875
+  proc newLit*(f: float): NimNode {.compileTime.} =
+    ## produces a new float literal node.
+    result = newNimNode(nnkFloatLit)
+    result.floatVal = f
+
+proc newLit*(f: float32): NimNode {.compileTime.} =
   ## produces a new float literal node.
-  result = newNimNode(nnkFloatLit)
+  result = newNimNode(nnkFloat32Lit)
   result.floatVal = f
 
+proc newLit*(f: float64): NimNode {.compileTime.} =
+  ## produces a new float literal node.
+  result = newNimNode(nnkFloat64Lit)
+  result.floatVal = f
+
+when compiles(float128):
+  proc newLit*(f: float128): NimNode {.compileTime.} =
+    ## produces a new float literal node.
+    result = newNimNode(nnkFloat128Lit)
+    result.floatVal = f
+
+proc newLit*(arg: object): NimNode {.compileTime.} =
+  result = nnkObjConstr.newTree(arg.type.getTypeInst[1])
+  for a, b in arg.fieldPairs:
+    result.add nnkExprColonExpr.newTree( newIdentNode(a), newLit(b) )
+
+proc newLit*[N,T](arg: array[N,T]): NimNode {.compileTime.} =
+  result = nnkBracket.newTree
+  for x in arg:
+    result.add newLit(x)
+
+proc newLit*[T](arg: seq[T]): NimNode {.compileTime.} =
+  result = nnkBracket.newTree
+  for x in arg:
+    result.add newLit(x)
+  result = nnkPrefix.newTree(bindSym"@", result)
+
+proc newLit*(arg: tuple): NimNode {.compileTime.} =
+  result = nnkPar.newTree
+  for a,b in arg.fieldPairs:
+    result.add nnkExprColonExpr.newTree( newIdentNode(a), newLit(b) )
+
 proc newLit*(s: string): NimNode {.compileTime.} =
   ## produces a new string literal node.
   result = newNimNode(nnkStrLit)
@@ -750,6 +841,8 @@ proc `$`*(node: NimNode): string {.compileTime.} =
     result = $node[0]
   of nnkAccQuoted:
     result = $node[0]
+  of nnkCommentStmt:
+    result = node.strVal
   else:
     badNodeKind node.kind, "$"
 
diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim
index 8d059dbbc..a374e80e8 100644
--- a/lib/pure/asynchttpserver.nim
+++ b/lib/pure/asynchttpserver.nim
@@ -127,7 +127,7 @@ proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] =
   i.inc protocol.parseInt(result.minor, i)
 
 proc sendStatus(client: AsyncSocket, status: string): Future[void] =
-  client.send("HTTP/1.1 " & status & "\c\L")
+  client.send("HTTP/1.1 " & status & "\c\L\c\L") 
 
 proc processClient(client: AsyncSocket, address: string,
                    callback: proc (request: Request):
diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim
index a104478ac..89b216b25 100644
--- a/lib/pure/asyncmacro.nim
+++ b/lib/pure/asyncmacro.nim
@@ -301,7 +301,7 @@ proc verifyReturnType(typeName: string) {.compileTime.} =
 proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
   ## This macro transforms a single procedure into a closure iterator.
   ## The ``async`` macro supports a stmtList holding multiple async procedures.
-  if prc.kind notin {nnkProcDef, nnkLambda, nnkMethodDef}:
+  if prc.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}:
       error("Cannot transform this node kind into an async proc." &
             " proc/method definition or lambda node expected.")
 
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index 323af5a38..5b6701a12 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -590,8 +590,11 @@ proc enlarge[A, B](t: var OrderedTable[A, B]) =
   swap(t.data, n)
   while h >= 0:
     var nxt = n[h].next
-    if isFilled(n[h].hcode):
-      var j = -1 - rawGetKnownHC(t, n[h].key, n[h].hcode)
+    let eh = n[h].hcode
+    if isFilled(eh):
+      var j: Hash = eh and maxHash(t)
+      while isFilled(t.data[j].hcode):
+        j = nextTry(j, maxHash(t))
       rawInsert(t, t.data, n[h].key, n[h].val, n[h].hcode, j)
     h = nxt
 
diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim
index c3390573a..603fee080 100644
--- a/lib/pure/concurrency/cpuinfo.nim
+++ b/lib/pure/concurrency/cpuinfo.nim
@@ -69,4 +69,4 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
     result = affinitySpaceTotal().int
   else:
     result = sysconf(SC_NPROCESSORS_ONLN)
-  if result <= 0: result = 1
+  if result <= 0: result = 0
diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim
index e8c8776c6..b015ed311 100644
--- a/lib/pure/hashes.nim
+++ b/lib/pure/hashes.nim
@@ -139,9 +139,14 @@ proc hash*(x: cstring): Hash =
   ## efficient hashing of null-terminated strings
   var h: Hash = 0
   var i = 0
-  while x[i] != 0.char:
-    h = h !& ord(x[i])
-    inc i
+  when defined(js):
+    while i < x.len:
+      h = h !& ord(x[i])
+      inc i
+  else:
+    while x[i] != 0.char:
+      h = h !& ord(x[i])
+      inc i
   result = !$h
 
 proc hash*(sBuf: string, sPos, ePos: int): Hash =
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 4f43177a8..909a2613f 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -62,7 +62,8 @@
 ##   let body = %*{
 ##       "data": "some text"
 ##   }
-##   echo client.request("http://some.api", httpMethod = HttpPost, body = $body)
+##   let response = client.request("http://some.api", httpMethod = HttpPost, body = $body)
+##   echo response.status
 ##
 ## Progress reporting
 ## ==================
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 6780ca164..e3d5191c6 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -1001,7 +1001,7 @@ proc escapeJson*(s: string; result: var string) =
   result.add("\"")
   for x in runes(s):
     var r = int(x)
-    if r >= 32 and r <= 127:
+    if r >= 32 and r <= 126:
       var c = chr(r)
       case c
       of '"': result.add("\\\"")
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index a8432b6f0..8037b31b0 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -235,7 +235,7 @@ when not defined(JS):
         x = x and (not (1'u64 shl (64'u64-12'u64-e) - 1'u64))
 
       result = cast[float64](x)
-    
+
     proc truncImpl(f: float32): float32 =
       const
         mask : uint32 = 0xFF
@@ -255,7 +255,7 @@ when not defined(JS):
         x = x and (not (1'u32 shl (32'u32-9'u32-e) - 1'u32))
 
       result = cast[float32](x)
-      
+
     proc trunc*(x: float64): float64 =
       if classify(x) in {fcZero, fcNegZero, fcNan, fcInf, fcNegInf}: return x
       result = truncImpl(x)
@@ -395,6 +395,12 @@ proc radToDeg*[T: float32|float64](d: T): T {.inline.} =
   ## Convert from radians to degrees
   result = T(d) / RadPerDeg
 
+proc sgn*[T: SomeNumber](x: T): int {.inline.} =
+  ## Sign function. Returns -1 for negative numbers and `NegInf`, 1 for
+  ## positive numbers and `Inf`, and 0 for positive zero, negative zero and
+  ## `NaN`.
+  ord(T(0) < x) - ord(x < T(0))
+
 proc `mod`*[T: float32|float64](x, y: T): T =
   ## Computes the modulo operation for float operators. Equivalent
   ## to ``x - y * floor(x/y)``. Note that the remainder will always
@@ -407,10 +413,13 @@ proc `mod`*[T: float32|float64](x, y: T): T =
 {.pop.}
 {.pop.}
 
-proc `^`*[T](x, y: T): T =
+proc `^`*[T](x: T, y: Natural): T =
   ## Computes ``x`` to the power ``y`. ``x`` must be non-negative, use
   ## `pow <#pow,float,float>` for negative exponents.
-  assert y >= T(0)
+  when compiles(y >= T(0)):
+    assert y >= T(0)
+  else:
+    assert T(y) >= T(0)
   var (x, y) = (x, y)
   result = 1
 
@@ -447,6 +456,7 @@ when isMainModule and not defined(JS):
   assert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0
   assert(erf(6.0) > erf(5.0))
   assert(erfc(6.0) < erfc(5.0))
+
 when isMainModule:
   # Function for approximate comparison of floats
   proc `==~`(x, y: float): bool = (abs(x-y) < 1e-9)
@@ -509,3 +519,21 @@ when isMainModule:
     doAssert(classify(trunc(-1e1000000'f32)) == fcNegInf)
     doAssert(classify(trunc(f_nan.float32)) == fcNan)
     doAssert(classify(trunc(0.0'f32)) == fcZero)
+
+  block: # sgn() tests
+    assert sgn(1'i8) == 1
+    assert sgn(1'i16) == 1
+    assert sgn(1'i32) == 1
+    assert sgn(1'i64) == 1
+    assert sgn(1'u8) == 1
+    assert sgn(1'u16) == 1
+    assert sgn(1'u32) == 1
+    assert sgn(1'u64) == 1
+    assert sgn(-12342.8844'f32) == -1
+    assert sgn(123.9834'f64) == 1
+    assert sgn(0'i32) == 0
+    assert sgn(0'f32) == 0
+    assert sgn(NegInf) == -1
+    assert sgn(Inf) == 1
+    assert sgn(NaN) == 0
+
diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim
index 307808556..5bdd3bc40 100644
--- a/lib/pure/parsecfg.nim
+++ b/lib/pure/parsecfg.nim
@@ -542,7 +542,6 @@ proc writeConfig*(dict: Config, filename: string) =
   let file = open(filename, fmWrite)
   defer: file.close()
   let fileStream = newFileStream(file)
-  defer: fileStream.close()
   dict.writeConfig(fileStream)
 
 proc getSectionValue*(dict: Config, section, key: string): string =
diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim
index 218f5ab81..23568edb9 100644
--- a/lib/pure/parseopt.nim
+++ b/lib/pure/parseopt.nim
@@ -149,26 +149,41 @@ proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} =
   ## retrieves the rest of the command line that has not been parsed yet.
   result = strip(substr(p.cmd, p.pos, len(p.cmd) - 1)).TaintedString
 
+iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key, val: TaintedString] =
+  ## This is an convenience iterator for iterating over the given OptParser object.
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##   var p = initOptParser("--left --debug:3 -l=4 -r:2")
+  ##   for kind, key, val in p.getopt():
+  ##     case kind
+  ##     of cmdArgument:
+  ##       filename = key
+  ##     of cmdLongOption, cmdShortOption:
+  ##       case key
+  ##       of "help", "h": writeHelp()
+  ##       of "version", "v": writeVersion()
+  ##     of cmdEnd: assert(false) # cannot happen
+  ##   if filename == "":
+  ##     # no filename has been given, so we show the help:
+  ##     writeHelp()
+  p.pos = 0
+  while true:
+    next(p)
+    if p.kind == cmdEnd: break
+    yield (p.kind, p.key, p.val)
+
 when declared(initOptParser):
   iterator getopt*(): tuple[kind: CmdLineKind, key, val: TaintedString] =
-    ## This is an convenience iterator for iterating over the command line.
-    ## This uses the OptParser object. Example:
+    ## This is an convenience iterator for iterating over the command line arguments.
+    ## This create a new OptParser object.
+    ## See above for a more detailed example
     ##
     ## .. code-block:: nim
-    ##   var
-    ##     filename = ""
     ##   for kind, key, val in getopt():
-    ##     case kind
-    ##     of cmdArgument:
-    ##       filename = key
-    ##     of cmdLongOption, cmdShortOption:
-    ##       case key
-    ##       of "help", "h": writeHelp()
-    ##       of "version", "v": writeVersion()
-    ##     of cmdEnd: assert(false) # cannot happen
-    ##   if filename == "":
-    ##     # no filename has been given, so we show the help:
-    ##     writeHelp()
+    ##     # this will iterate over all arguments passed to the cmdline.
+    ##     continue
+    ##
     var p = initOptParser()
     while true:
       next(p)
diff --git a/lib/pure/parseopt2.nim b/lib/pure/parseopt2.nim
index 7fd9c60fe..2e8dbe140 100644
--- a/lib/pure/parseopt2.nim
+++ b/lib/pure/parseopt2.nim
@@ -123,26 +123,41 @@ type
 
 {.deprecated: [TGetoptResult: GetoptResult].}
 
+iterator getopt*(p: var OptParser): GetoptResult =
+  ## This is an convenience iterator for iterating over the given OptParser object.
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##   var p = initOptParser("--left --debug:3 -l=4 -r:2")
+  ##   for kind, key, val in p.getopt():
+  ##     case kind
+  ##     of cmdArgument:
+  ##       filename = key
+  ##     of cmdLongOption, cmdShortOption:
+  ##       case key
+  ##       of "help", "h": writeHelp()
+  ##       of "version", "v": writeVersion()
+  ##     of cmdEnd: assert(false) # cannot happen
+  ##   if filename == "":
+  ##     # no filename has been given, so we show the help:
+  ##     writeHelp()
+  p.pos = 0
+  while true:
+    next(p)
+    if p.kind == cmdEnd: break
+    yield (p.kind, p.key, p.val)
+
 when declared(paramCount):
   iterator getopt*(): GetoptResult =
-    ## This is an convenience iterator for iterating over the command line.
-    ## This uses the OptParser object. Example:
+    ## This is an convenience iterator for iterating over the command line arguments.
+    ## This create a new OptParser object.
+    ## See above for a more detailed example
     ##
     ## .. code-block:: nim
-    ##   var
-    ##     filename = ""
     ##   for kind, key, val in getopt():
-    ##     case kind
-    ##     of cmdArgument:
-    ##       filename = key
-    ##     of cmdLongOption, cmdShortOption:
-    ##       case key
-    ##       of "help", "h": writeHelp()
-    ##       of "version", "v": writeVersion()
-    ##     of cmdEnd: assert(false) # cannot happen
-    ##   if filename == "":
-    ##     # no filename has been given, so we show the help:
-    ##     writeHelp()
+    ##     # this will iterate over all arguments passed to the cmdline.
+    ##     continue
+    ##
     var p = initOptParser()
     while true:
       next(p)
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index 5c978a2f8..6a52e2cd5 100644
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -371,7 +371,7 @@ proc esc(c: char, reserved = {'\0'..'\255'}): string =
   of '\a': result = "\\a"
   of '\\': result = "\\\\"
   of 'a'..'z', 'A'..'Z', '0'..'9', '_': result = $c
-  elif c < ' ' or c >= '\128': result = '\\' & $ord(c)
+  elif c < ' ' or c >= '\127': result = '\\' & $ord(c)
   elif c in reserved: result = '\\' & c
   else: result = $c
 
diff --git a/lib/pure/random.nim b/lib/pure/random.nim
index 1f750edcd..8a32f7d9a 100644
--- a/lib/pure/random.nim
+++ b/lib/pure/random.nim
@@ -123,7 +123,8 @@ when not defined(nimscript):
       proc getMil(t: Time): int {.importcpp: "getTime", nodecl.}
       randomize(getMil times.getTime())
     else:
-      randomize(int times.getTime())
+      let time = int(times.epochTime() * 1_000_000_000)
+      randomize(time)
 
 {.pop.}
 
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index eea06f4ce..438b48beb 100644
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -334,12 +334,16 @@ when not defined(js):
     if result > 0:
       copyMem(buffer, addr(s.data[s.pos]), result)
       inc(s.pos, result)
+    else:
+      result = 0
 
   proc ssPeekData(s: Stream, buffer: pointer, bufLen: int): int =
     var s = StringStream(s)
     result = min(bufLen, s.data.len - s.pos)
     if result > 0:
       copyMem(buffer, addr(s.data[s.pos]), result)
+    else:
+      result = 0
 
   proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) =
     var s = StringStream(s)
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 458c22f3a..20b2657f6 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -1643,7 +1643,7 @@ proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
   ## * replaces any ``\`` by ``\\``
   ## * replaces any ``'`` by ``\'``
   ## * replaces any ``"`` by ``\"``
-  ## * replaces any other character in the set ``{'\0'..'\31', '\128'..'\255'}``
+  ## * replaces any other character in the set ``{'\0'..'\31', '\127'..'\255'}``
   ##   by ``\xHH`` where ``HH`` is its hexadecimal value.
   ## The procedure has been designed so that its output is usable for many
   ## different common syntaxes. The resulting string is prefixed with
@@ -1653,7 +1653,7 @@ proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
   result.add(prefix)
   for c in items(s):
     case c
-    of '\0'..'\31', '\128'..'\255':
+    of '\0'..'\31', '\127'..'\255':
       add(result, "\\x")
       add(result, toHex(ord(c), 2))
     of '\\': add(result, "\\\\")
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index bad003a3e..eff912d12 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -81,7 +81,7 @@ when defined(posix) and not defined(JS):
 elif defined(windows):
   import winlean
 
-  when defined(vcc) or defined(bcc):
+  when defined(vcc) or defined(bcc) or defined(icl):
     # newest version of Visual C++ defines time_t to be of 64 bits
     type TimeImpl {.importc: "time_t", header: "<time.h>".} = int64
     # visual c's c runtime exposes these under a different name
diff --git a/lib/system.nim b/lib/system.nim
index fdc4c7db0..0e94bcc23 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1895,7 +1895,7 @@ const
   NimMinor*: int = 17
     ## is the minor number of Nim's version.
 
-  NimPatch*: int = 0
+  NimPatch*: int = 1
     ## is the patch number of Nim's version.
 
   NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
@@ -2047,6 +2047,14 @@ proc clamp*[T](x, a, b: T): T =
   if x > b: return b
   return x
 
+proc len*[T: Ordinal](x: Slice[T]): int {.noSideEffect, inline.} =
+  ## length of ordinal slice, when x.b < x.a returns zero length
+  ##
+  ## .. code-block:: Nim
+  ##   assert((0..5).len == 6)
+  ##   assert((5..2).len == 0)
+  result = max(0, ord(x.b) - ord(x.a) + 1)
+
 iterator items*[T](a: openArray[T]): T {.inline.} =
   ## iterates over each item of `a`.
   var i = 0
@@ -2441,18 +2449,6 @@ when false:
 # ----------------- GC interface ---------------------------------------------
 
 when not defined(nimscript) and hasAlloc:
-  proc GC_disable*() {.rtl, inl, benign.}
-    ## disables the GC. If called n-times, n calls to `GC_enable` are needed to
-    ## reactivate the GC. Note that in most circumstances one should only disable
-    ## the mark and sweep phase with `GC_disableMarkAndSweep`.
-
-  proc GC_enable*() {.rtl, inl, benign.}
-    ## enables the GC again.
-
-  proc GC_fullCollect*() {.rtl, benign.}
-    ## forces a full garbage collection pass.
-    ## Ordinary code does not need to call this (and should not).
-
   type
     GC_Strategy* = enum ## the strategy the GC should use for the application
       gcThroughput,      ## optimize for throughput
@@ -2462,33 +2458,87 @@ when not defined(nimscript) and hasAlloc:
 
   {.deprecated: [TGC_Strategy: GC_Strategy].}
 
-  proc GC_setStrategy*(strategy: GC_Strategy) {.rtl, deprecated, benign.}
-    ## tells the GC the desired strategy for the application.
-    ## **Deprecated** since version 0.8.14. This has always been a nop.
-
-  proc GC_enableMarkAndSweep*() {.rtl, benign.}
-  proc GC_disableMarkAndSweep*() {.rtl, benign.}
-    ## the current implementation uses a reference counting garbage collector
-    ## with a seldomly run mark and sweep phase to free cycles. The mark and
-    ## sweep phase may take a long time and is not needed if the application
-    ## does not create cycles. Thus the mark and sweep phase can be deactivated
-    ## and activated separately from the rest of the GC.
-
-  proc GC_getStatistics*(): string {.rtl, benign.}
-    ## returns an informative string about the GC's activity. This may be useful
-    ## for tweaking.
-
-  proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.}
-  proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.}
-  proc GC_ref*(x: string) {.magic: "GCref", benign.}
-    ## marks the object `x` as referenced, so that it will not be freed until
-    ## it is unmarked via `GC_unref`. If called n-times for the same object `x`,
-    ## n calls to `GC_unref` are needed to unmark `x`.
-
-  proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.}
-  proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.}
-  proc GC_unref*(x: string) {.magic: "GCunref", benign.}
-    ## see the documentation of `GC_ref`.
+  when not defined(JS):
+    proc GC_disable*() {.rtl, inl, benign.}
+      ## disables the GC. If called n-times, n calls to `GC_enable` are needed to
+      ## reactivate the GC. Note that in most circumstances one should only disable
+      ## the mark and sweep phase with `GC_disableMarkAndSweep`.
+
+    proc GC_enable*() {.rtl, inl, benign.}
+      ## enables the GC again.
+
+    proc GC_fullCollect*() {.rtl, benign.}
+      ## forces a full garbage collection pass.
+      ## Ordinary code does not need to call this (and should not).
+
+    proc GC_setStrategy*(strategy: GC_Strategy) {.rtl, deprecated, benign.}
+      ## tells the GC the desired strategy for the application.
+      ## **Deprecated** since version 0.8.14. This has always been a nop.
+
+    proc GC_enableMarkAndSweep*() {.rtl, benign.}
+    proc GC_disableMarkAndSweep*() {.rtl, benign.}
+      ## the current implementation uses a reference counting garbage collector
+      ## with a seldomly run mark and sweep phase to free cycles. The mark and
+      ## sweep phase may take a long time and is not needed if the application
+      ## does not create cycles. Thus the mark and sweep phase can be deactivated
+      ## and activated separately from the rest of the GC.
+
+    proc GC_getStatistics*(): string {.rtl, benign.}
+      ## returns an informative string about the GC's activity. This may be useful
+      ## for tweaking.
+
+    proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.}
+    proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.}
+    proc GC_ref*(x: string) {.magic: "GCref", benign.}
+      ## marks the object `x` as referenced, so that it will not be freed until
+      ## it is unmarked via `GC_unref`. If called n-times for the same object `x`,
+      ## n calls to `GC_unref` are needed to unmark `x`.
+
+    proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.}
+    proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.}
+    proc GC_unref*(x: string) {.magic: "GCunref", benign.}
+      ## see the documentation of `GC_ref`.
+
+  else:
+    template GC_disable* =
+      {.warning: "GC_disable is a no-op in JavaScript".}
+
+    template GC_enable* =
+      {.warning: "GC_enable is a no-op in JavaScript".}
+
+    template GC_fullCollect* =
+      {.warning: "GC_fullCollect is a no-op in JavaScript".}
+
+    template GC_setStrategy* =
+      {.warning: "GC_setStrategy is a no-op in JavaScript".}
+
+    template GC_enableMarkAndSweep* =
+      {.warning: "GC_enableMarkAndSweep is a no-op in JavaScript".}
+
+    template GC_disableMarkAndSweep* =
+      {.warning: "GC_disableMarkAndSweep is a no-op in JavaScript".}
+
+    template GC_ref*[T](x: ref T) =
+      {.warning: "GC_ref is a no-op in JavaScript".}
+
+    template GC_ref*[T](x: seq[T]) =
+      {.warning: "GC_ref is a no-op in JavaScript".}
+
+    template GC_ref*(x: string) =
+      {.warning: "GC_ref is a no-op in JavaScript".}
+
+    template GC_unref*[T](x: ref T) =
+      {.warning: "GC_unref is a no-op in JavaScript".}
+
+    template GC_unref*[T](x: seq[T]) =
+      {.warning: "GC_unref is a no-op in JavaScript".}
+
+    template GC_unref*(x: string) =
+      {.warning: "GC_unref is a no-op in JavaScript".}
+
+    template GC_getStatistics*(): string =
+      {.warning: "GC_disableMarkAndSweep is a no-op in JavaScript".}
+      ""
 
 template accumulateResult*(iter: untyped) =
   ## helps to convert an iterator to a proc.
@@ -3223,16 +3273,6 @@ when not defined(JS): #and not defined(nimscript):
 
 elif defined(JS):
   # Stubs:
-  proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = discard
-
-  proc GC_disable() = discard
-  proc GC_enable() = discard
-  proc GC_fullCollect() = discard
-  proc GC_setStrategy(strategy: GC_Strategy) = discard
-  proc GC_enableMarkAndSweep() = discard
-  proc GC_disableMarkAndSweep() = discard
-  proc GC_getStatistics(): string = return ""
-
   proc getOccupiedMem(): int = return -1
   proc getFreeMem(): int = return -1
   proc getTotalMem(): int = return -1
@@ -3734,7 +3774,8 @@ proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} =
 
 when hasAlloc and not defined(nimscript) and not defined(JS):
   proc deepCopy*[T](x: var T, y: T) {.noSideEffect, magic: "DeepCopy".} =
-    ## performs a deep copy of `x`. This is also used by the code generator
+    ## performs a deep copy of `y` and copies it into `x`.
+    ## This is also used by the code generator
     ## for the implementation of ``spawn``.
     discard
 
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
index bcbc5d92f..78db96e77 100644
--- a/lib/system/alloc.nim
+++ b/lib/system/alloc.nim
@@ -9,7 +9,6 @@
 
 # Low level allocator for Nim. Has been designed to support the GC.
 # TODO:
-# - eliminate "used" field
 # - make searching for block O(1)
 {.push profiler:off.}
 
diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim
index b0eb25616..cd03d2a54 100644
--- a/lib/system/gc_common.nim
+++ b/lib/system/gc_common.nim
@@ -25,6 +25,13 @@ when defined(nimTypeNames):
         c_fprintf(stdout, "[Heap] %s: #%ld; bytes: %ld\n", it.name, it.instances, it.sizes)
       it = it.nextType
 
+  when defined(nimGcRefLeak):
+    proc oomhandler() =
+      c_fprintf(stdout, "[Heap] ROOTS: #%ld\n", gch.additionalRoots.len)
+      writeLeaks()
+
+    outOfMemHook = oomhandler
+
 template decTypeSize(cell, t) =
   # XXX this needs to use atomics for multithreaded apps!
   when defined(nimTypeNames):
diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim
index 5896af88e..a97e974a1 100644
--- a/lib/system/gc_ms.nim
+++ b/lib/system/gc_ms.nim
@@ -142,11 +142,54 @@ proc doOperation(p: pointer, op: WalkOp) {.benign.}
 proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.}
 # we need the prototype here for debugging purposes
 
+when defined(nimGcRefLeak):
+  const
+    MaxTraceLen = 20 # tracking the last 20 calls is enough
+
+  type
+    GcStackTrace = object
+      lines: array[0..MaxTraceLen-1, cstring]
+      files: array[0..MaxTraceLen-1, cstring]
+
+  proc captureStackTrace(f: PFrame, st: var GcStackTrace) =
+    const
+      firstCalls = 5
+    var
+      it = f
+      i = 0
+      total = 0
+    while it != nil and i <= high(st.lines)-(firstCalls-1):
+      # the (-1) is for the "..." entry
+      st.lines[i] = it.procname
+      st.files[i] = it.filename
+      inc(i)
+      inc(total)
+      it = it.prev
+    var b = it
+    while it != nil:
+      inc(total)
+      it = it.prev
+    for j in 1..total-i-(firstCalls-1):
+      if b != nil: b = b.prev
+    if total != i:
+      st.lines[i] = "..."
+      st.files[i] = "..."
+      inc(i)
+    while b != nil and i <= high(st.lines):
+      st.lines[i] = b.procname
+      st.files[i] = b.filename
+      inc(i)
+      b = b.prev
+
+  var ax: array[10_000, GcStackTrace]
+
 proc nimGCref(p: pointer) {.compilerProc.} =
   # we keep it from being collected by pretending it's not even allocated:
   when false:
     when withBitvectors: excl(gch.allocated, usrToCell(p))
     else: usrToCell(p).refcount = rcBlack
+  when defined(nimGcRefLeak):
+    captureStackTrace(framePtr, ax[gch.additionalRoots.len])
   add(gch.additionalRoots, usrToCell(p))
 
 proc nimGCunref(p: pointer) {.compilerProc.} =
@@ -157,6 +200,8 @@ proc nimGCunref(p: pointer) {.compilerProc.} =
   while i >= 0:
     if d[i] == cell:
       d[i] = d[L]
+      when defined(nimGcRefLeak):
+        ax[i] = ax[L]
       dec gch.additionalRoots.len
       break
     dec(i)
@@ -164,6 +209,16 @@ proc nimGCunref(p: pointer) {.compilerProc.} =
     when withBitvectors: incl(gch.allocated, usrToCell(p))
     else: usrToCell(p).refcount = rcWhite
 
+when defined(nimGcRefLeak):
+  proc writeLeaks() =
+    for i in 0..gch.additionalRoots.len-1:
+      c_fprintf(stdout, "[Heap] NEW STACK TRACE\n")
+      for ii in 0..MaxTraceLen-1:
+        let line = ax[i].lines[ii]
+        let file = ax[i].files[ii]
+        if isNil(line): break
+        c_fprintf(stdout, "[Heap] %s(%s)\n", file, line)
+
 include gc_common
 
 proc prepareDealloc(cell: PCell) =
diff --git a/lib/system/gc_stack.nim b/lib/system/gc_stack.nim
index 3eda08df9..e7b9f65a7 100644
--- a/lib/system/gc_stack.nim
+++ b/lib/system/gc_stack.nim
@@ -79,7 +79,7 @@ template withRegion*(r: MemRegion; body: untyped) =
   try:
     body
   finally:
-    r = tlRegion
+    #r = tlRegion
     tlRegion = oldRegion
 
 template inc(p: pointer, s: int) =
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index 431f84bfd..5b5ba9490 100644
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -255,12 +255,21 @@ elif defined(gogc):
         next_gc: uint64          # next GC (in heap_alloc time)
         last_gc: uint64          # last GC (in absolute time)
         pause_total_ns: uint64
-        pause_ns: array[256, uint64]
+        pause_ns: array[256, uint64] # circular buffer of recent gc pause lengths
+        pause_end: array[256, uint64] # circular buffer of recent gc end times (nanoseconds since 1970)
         numgc: uint32
+        numforcedgc: uint32      # number of user-forced GCs
+        gc_cpu_fraction: float64 # fraction of CPU time used by GC
         enablegc: cbool
         debuggc: cbool
         # Statistics about allocation size classes.
         by_size: array[goNumSizeClasses, goMStats_inner_struct]
+        # Statistics below here are not exported to MemStats directly.
+        tinyallocs: uint64       # number of tiny allocations that didn't cause actual allocation; not exported to go directly
+        gc_trigger: uint64
+        heap_live: uint64
+        heap_scan: uint64
+        heap_marked: uint64
 
   proc goRuntime_ReadMemStats(a2: ptr goMStats) {.cdecl,
     importc: "runtime_ReadMemStats",
diff --git a/lib/system/repr.nim b/lib/system/repr.nim
index d9aa03b53..ab02c58a2 100644
--- a/lib/system/repr.nim
+++ b/lib/system/repr.nim
@@ -49,7 +49,7 @@ proc reprStrAux(result: var string, s: cstring; len: int) =
     of '"': add result, "\\\""
     of '\\': add result, "\\\\" # BUGFIX: forgotten
     of '\10': add result, "\\10\"\n\"" # " \n " # better readability
-    of '\128' .. '\255', '\0'..'\9', '\11'..'\31':
+    of '\127' .. '\255', '\0'..'\9', '\11'..'\31':
       add result, "\\" & reprInt(ord(c))
     else:
       result.add(c)
@@ -68,7 +68,7 @@ proc reprChar(x: char): string {.compilerRtl.} =
   case x
   of '"': add result, "\\\""
   of '\\': add result, "\\\\"
-  of '\128' .. '\255', '\0'..'\31': add result, "\\" & reprInt(ord(x))
+  of '\127' .. '\255', '\0'..'\31': add result, "\\" & reprInt(ord(x))
   else: add result, x
   add result, "\'"
 
diff --git a/lib/system/reprjs.nim b/lib/system/reprjs.nim
index 6b0e32191..5c265a891 100644
--- a/lib/system/reprjs.nim
+++ b/lib/system/reprjs.nim
@@ -44,7 +44,7 @@ proc reprChar(x: char): string {.compilerRtl.} =
   case x
   of '"': add(result, "\\\"")
   of '\\': add(result, "\\\\")
-  of '\128'..'\255', '\0'..'\31': add( result, "\\" & reprInt(ord(x)) )
+  of '\127'..'\255', '\0'..'\31': add( result, "\\" & reprInt(ord(x)) )
   else: add(result, x)
   add(result, "\'")
 
@@ -56,7 +56,7 @@ proc reprStrAux(result: var string, s: cstring, len: int) =
     of '"': add(result, "\\\"")
     of '\\': add(result, "\\\\")
     of '\10': add(result, "\\10\"\n\"")
-    of '\128'..'\255', '\0'..'\9', '\11'..'\31':
+    of '\127'..'\255', '\0'..'\9', '\11'..'\31':
       add( result, "\\" & reprInt(ord(c)) )
     else:
       add( result, reprInt(ord(c)) ) # Not sure about this.
diff --git a/lib/system/syslocks.nim b/lib/system/syslocks.nim
index f61b887ad..6569f4f9f 100644
--- a/lib/system/syslocks.nim
+++ b/lib/system/syslocks.nim
@@ -117,6 +117,12 @@ else:
       when defined(linux) and defined(amd64):
         abi: array[48 div sizeof(clonglong), clonglong]
 
+    SysCondAttr {.importc: "pthread_condattr_t", pure, final
+               header: """#include <sys/types.h>
+                          #include <pthread.h>""".} = object
+      when defined(linux) and defined(amd64):
+        abi: array[4 div sizeof(cint), cint]  # actually a cint
+
     SysLockType = distinct cint
 
   proc initSysLockAux(L: var SysLockObj, attr: ptr SysLockAttr) {.
@@ -185,7 +191,7 @@ else:
       importc: "pthread_mutexattr_settype", header: "<pthread.h>", noSideEffect.}
 
   else:
-    proc initSysCondAux(cond: var SysCondObj, cond_attr: pointer) {.
+    proc initSysCondAux(cond: var SysCondObj, cond_attr: ptr SysCondAttr = nil) {.
       importc: "pthread_cond_init", header: "<pthread.h>", noSideEffect.}
     proc deinitSysCondAux(cond: var SysCondObj) {.noSideEffect,
       importc: "pthread_cond_destroy", header: "<pthread.h>".}
@@ -196,7 +202,7 @@ else:
       importc: "pthread_cond_signal", header: "<pthread.h>", noSideEffect.}
 
     when defined(ios):
-      proc initSysCond(cond: var SysCond, cond_attr: pointer = nil) =
+      proc initSysCond(cond: var SysCond, cond_attr: ptr SysCondAttr = nil) =
         cond = cast[SysCond](c_malloc(sizeof(SysCondObj)))
         initSysCondAux(cond[], cond_attr)
 
@@ -209,7 +215,7 @@ else:
       template signalSysCond(cond: var SysCond) =
         signalSysCondAux(cond[])
     else:
-      template initSysCond(cond: var SysCond, cond_attr: pointer = nil) =
+      template initSysCond(cond: var SysCond, cond_attr: ptr SysCondAttr = nil) =
         initSysCondAux(cond, cond_attr)
       template deinitSysCond(cond: var SysCond) =
         deinitSysCondAux(cond)
diff --git a/lib/system/threads.nim b/lib/system/threads.nim
index d1012e9c5..49b13576c 100644
--- a/lib/system/threads.nim
+++ b/lib/system/threads.nim
@@ -264,7 +264,17 @@ else:
 
     proc getThreadId*(): int =
       result = int(lwp_gettid())
-  elif defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd):
+  elif defined(openbsd):
+    proc getthrid(): int32 {.importc: "getthrid", header: "<unistd.h>".}
+
+    proc getThreadId*(): int =
+      result = int(getthrid())
+  elif defined(netbsd):
+    proc lwp_self(): int32 {.importc: "_lwp_self", header: "<lwp.h>".}
+
+    proc getThreadId*(): int =
+      result = int(lwp_self())
+  elif defined(macosx) or defined(freebsd):
     proc pthread_threadid_np(y: pointer; x: var uint64): cint {.importc, header: "pthread.h".}
 
     proc getThreadId*(): int =
diff --git a/readme.md b/readme.md
index 30cc14079..5e50bbc41 100644
--- a/readme.md
+++ b/readme.md
@@ -96,9 +96,8 @@ started contributing, you should familiarize yourself with the repository struct
 
 * ``bin/``, ``build/`` - these directories are empty, but are used when Nim is built.
 * ``compiler/`` - the compiler source code. Also includes nimfix, and plugins within
-  ``compiler/nimfix`` and ``compiler/plugins`` respectively. Nimsuggest was moved to
-  the [``nim-lang/nimsuggest``][nimsuggest-repo] repository, though it previously also 
-  lived within the ``compiler/`` directory.
+  ``compiler/nimfix`` and ``compiler/plugins`` respectively.
+* ``nimsuggest`` - the nimsuggest tool that previously lived in the [``nim-lang/nimsuggest``][nimsuggest-repo] repository. 
 * ``config/`` - the configuration for the compiler and documentation generator.
 * ``doc/`` - the documentation files in reStructuredText format.
 * ``lib/`` - the standard library, including:
diff --git a/tests/arithm/tshr.nim b/tests/arithm/tshr.nim
new file mode 100644
index 000000000..e9b72f1df
--- /dev/null
+++ b/tests/arithm/tshr.nim
@@ -0,0 +1,20 @@
+discard """
+  output: ''''''
+"""
+
+proc T() =
+    let VI = -8
+    let VI64 = -8'i64
+    let VI32 = -8'i32
+    let VI16 = -8'i16
+    let VI8 = -8'i8
+    doAssert( (VI shr 1) == 9223372036854775804)
+    doAssert( (VI64 shr 1) == 9223372036854775804)
+    doAssert( (VI32 shr 1) == 2147483644)
+    doAssert( (VI16 shr 1) == 32764)
+    doAssert( (VI8 shr 1) == 124)
+
+
+T()
+static:
+    T()
diff --git a/tests/async/tlambda.nim b/tests/async/tlambda.nim
index e0ff1f483..d187c0d50 100644
--- a/tests/async/tlambda.nim
+++ b/tests/async/tlambda.nim
@@ -51,5 +51,8 @@ proc main() =
 
   var builder = newBuilder()
 
+  # Test {.async.} pragma with do notation: #5995
+  builder.client = newClient("builder") do(client: Client, msg: JsonNode) {.async.}:
+    await onMessage(builder, msg)
 
 main()
diff --git a/tests/bind/tinvalidbindtypedesc.nim b/tests/bind/tinvalidbindtypedesc.nim
index 5b2f51110..7704d2cb7 100644
--- a/tests/bind/tinvalidbindtypedesc.nim
+++ b/tests/bind/tinvalidbindtypedesc.nim
@@ -1,6 +1,6 @@
 discard """
   line: 10
-  errormsg: "type mismatch: got (typedesc[float], string)"
+  errormsg: "type mismatch: got (type float, string)"
 """
 
 proc foo(T: typedesc; some: T) =
diff --git a/tests/bind/tnicerrorforsymchoice.nim b/tests/bind/tnicerrorforsymchoice.nim
index bd00188fa..1431720e0 100644
--- a/tests/bind/tnicerrorforsymchoice.nim
+++ b/tests/bind/tnicerrorforsymchoice.nim
@@ -1,6 +1,6 @@
 discard """
   line: 18
-  errormsg: "type mismatch: got (proc (s: TScgi) | proc (client: AsyncSocket, headers: StringTableRef, input: string){.noSideEffect, gcsafe, locks: 0.}"
+  errormsg: "type mismatch: got (proc (s: TScgi: ScgiState or AsyncScgiState) | proc (client: AsyncSocket, headers: StringTableRef, input: string){.noSideEffect, gcsafe, locks: 0.}"
 """
 
 #bug #442
diff --git a/tests/concepts/t3414.nim b/tests/concepts/t3414.nim
new file mode 100644
index 000000000..d45973034
--- /dev/null
+++ b/tests/concepts/t3414.nim
@@ -0,0 +1,22 @@
+type
+  View[T] = concept v
+    v.empty is bool
+    v.front is T
+    popFront v
+
+proc find(view: View; target: View.T): View =
+  result = view
+
+  while not result.empty:
+    if view.front == target:
+      return
+
+    mixin popFront
+    popFront result
+
+proc popFront[T](s: var seq[T]) = discard
+proc empty[T](s: seq[T]): bool = false
+
+var s1 = @[1, 2, 3]
+let s2 = s1.find(10)
+
diff --git a/tests/concepts/t4982.nim b/tests/concepts/t4982.nim
new file mode 100644
index 000000000..9d82c83c9
--- /dev/null
+++ b/tests/concepts/t4982.nim
@@ -0,0 +1,18 @@
+discard """
+errormsg: "undeclared identifier: 'x'"
+line: 10
+"""
+
+import typetraits # without this import the program compiles (and echos false)
+
+type
+  SomeTestConcept = concept t
+    x.name is string # typo: t.name was intended (which would result in echo true)
+
+type
+  TestClass = ref object of RootObj
+    name: string
+
+var test = TestClass(name: "mytest")
+echo $(test is SomeTestConcept)
+
diff --git a/tests/concepts/t5888.nim b/tests/concepts/t5888.nim
new file mode 100644
index 000000000..dbbab8c4c
--- /dev/null
+++ b/tests/concepts/t5888.nim
@@ -0,0 +1,26 @@
+discard """
+output: '''
+true
+true
+true
+f
+0
+'''
+"""
+
+import t5888lib/ca, t5888lib/opt
+
+type LocalCA = ca.CA
+
+proc f(c: CA) =
+  echo "f"
+  echo c.x
+
+var o = new(Opt)
+
+echo o is CA
+echo o is LocalCA
+echo o is ca.CA
+
+o.f()
+
diff --git a/tests/concepts/t5888lib/ca.nim b/tests/concepts/t5888lib/ca.nim
new file mode 100644
index 000000000..4a811f797
--- /dev/null
+++ b/tests/concepts/t5888lib/ca.nim
@@ -0,0 +1,4 @@
+type
+  CA* = concept c
+    c.x is int
+
diff --git a/tests/concepts/t5888lib/opt.nim b/tests/concepts/t5888lib/opt.nim
new file mode 100644
index 000000000..65d16addc
--- /dev/null
+++ b/tests/concepts/t5888lib/opt.nim
@@ -0,0 +1,6 @@
+import ca
+
+type
+  Opt* = object
+    x*: int
+
diff --git a/tests/concepts/t5968.nim b/tests/concepts/t5968.nim
new file mode 100644
index 000000000..adb374c65
--- /dev/null
+++ b/tests/concepts/t5968.nim
@@ -0,0 +1,20 @@
+discard """
+  exitcode: 0
+"""
+
+type
+  Enumerable[T] = concept e
+    for it in e:
+      it is T
+
+proc cmap[T, G](e: Enumerable[T], fn: proc(t: T): G): seq[G] =
+  result = @[]
+  for it in e: result.add(fn(it))
+
+import json
+
+var x = %["hello", "world"]
+
+var z = x.cmap(proc(it: JsonNode): string = it.getStr & "!")
+assert z == @["hello!", "world!"]
+
diff --git a/tests/concepts/t5983.nim b/tests/concepts/t5983.nim
new file mode 100644
index 000000000..e69647448
--- /dev/null
+++ b/tests/concepts/t5983.nim
@@ -0,0 +1,22 @@
+discard """
+  output: "20.0 USD"
+"""
+
+import typetraits
+
+const currencies = ["USD", "EUR"] # in real code 120 currencies
+
+type USD* = distinct float # in real code 120 types generates using macro
+type EUR* = distinct float
+
+type CurrencyAmount = concept c
+  type t = c.type
+  const name = c.type.name
+  name in currencies
+
+proc `$`(x: CurrencyAmount): string =
+  $float(x) & " " & x.name
+
+let amount = 20.USD
+echo amount
+
diff --git a/tests/concepts/templatesinconcepts.nim b/tests/concepts/templatesinconcepts.nim
new file mode 100644
index 000000000..292b97ea6
--- /dev/null
+++ b/tests/concepts/templatesinconcepts.nim
@@ -0,0 +1,56 @@
+import typetraits
+
+template typeLen(x): int = x.type.name.len
+
+template bunchOfChecks(x) =
+  x.typeLen > 3
+  x != 10 is bool
+
+template stmtListExprTmpl(x: untyped): untyped =
+  x is int
+  x
+
+type
+  Obj = object
+    x: int
+
+  Gen[T] = object
+    x: T
+
+  Eq = concept x, y
+    (x == y) is bool
+
+  NotEq = concept x, y
+    (x != y) is bool
+
+  ConceptUsingTemplate1 = concept x
+    echo x
+    sizeof(x) is int
+    bunchOfChecks x
+
+  ConceptUsingTemplate2 = concept x
+    stmtListExprTmpl x
+
+template ok(x) =
+  static: assert(x)
+
+template no(x) =
+  static: assert(not(x))
+
+ok int is Eq
+ok int is NotEq
+ok string is Eq
+ok string is NotEq
+ok Obj is Eq
+ok Obj is NotEq
+ok Gen[string] is Eq
+ok Gen[int] is NotEq
+
+no int is ConceptUsingTemplate1
+ok float is ConceptUsingTemplate1
+no string is ConceptUsingTemplate1
+
+ok int is ConceptUsingTemplate2
+no float is ConceptUsingTemplate2
+no string is ConceptUsingTemplate2
+
diff --git a/tests/concepts/texplain.nim b/tests/concepts/texplain.nim
index 25a075fd1..417d1e502 100644
--- a/tests/concepts/texplain.nim
+++ b/tests/concepts/texplain.nim
@@ -9,33 +9,33 @@ proc e(o: ExplainedConcept): int
 texplain.nim(65, 6) ExplainedConcept: undeclared field: 'foo'
 texplain.nim(65, 6) ExplainedConcept: undeclared field: '.'
 texplain.nim(65, 6) ExplainedConcept: expression '.' cannot be called
-texplain.nim(65, 5) ExplainedConcept: type class predicate failed
+texplain.nim(65, 5) ExplainedConcept: concept predicate failed
 texplain.nim(66, 6) ExplainedConcept: undeclared field: 'bar'
 texplain.nim(66, 6) ExplainedConcept: undeclared field: '.'
 texplain.nim(66, 6) ExplainedConcept: expression '.' cannot be called
-texplain.nim(65, 5) ExplainedConcept: type class predicate failed
+texplain.nim(65, 5) ExplainedConcept: concept predicate failed
 
 texplain.nim(105, 10) Hint: Non-matching candidates for e(10)
 proc e(o: ExplainedConcept): int
 texplain.nim(65, 6) ExplainedConcept: undeclared field: 'foo'
 texplain.nim(65, 6) ExplainedConcept: undeclared field: '.'
 texplain.nim(65, 6) ExplainedConcept: expression '.' cannot be called
-texplain.nim(65, 5) ExplainedConcept: type class predicate failed
+texplain.nim(65, 5) ExplainedConcept: concept predicate failed
 texplain.nim(66, 6) ExplainedConcept: undeclared field: 'bar'
 texplain.nim(66, 6) ExplainedConcept: undeclared field: '.'
 texplain.nim(66, 6) ExplainedConcept: expression '.' cannot be called
-texplain.nim(65, 5) ExplainedConcept: type class predicate failed
+texplain.nim(65, 5) ExplainedConcept: concept predicate failed
 
 texplain.nim(109, 20) Error: type mismatch: got (NonMatchingType)
 but expected one of: 
 proc e(o: ExplainedConcept): int
-texplain.nim(65, 5) ExplainedConcept: type class predicate failed
+texplain.nim(65, 5) ExplainedConcept: concept predicate failed
 proc e(i: int): int
 
 texplain.nim(110, 20) Error: type mismatch: got (NonMatchingType)
 but expected one of: 
 proc r(o: RegularConcept): int
-texplain.nim(69, 5) RegularConcept: type class predicate failed
+texplain.nim(69, 5) RegularConcept: concept predicate failed
 proc r[T](a: SomeNumber; b: T; c: auto)
 proc r(i: string): int
 
@@ -49,12 +49,12 @@ proc f(o: NestedConcept)
 texplain.nim(69, 6) RegularConcept: undeclared field: 'foo'
 texplain.nim(69, 6) RegularConcept: undeclared field: '.'
 texplain.nim(69, 6) RegularConcept: expression '.' cannot be called
-texplain.nim(69, 5) RegularConcept: type class predicate failed
+texplain.nim(69, 5) RegularConcept: concept predicate failed
 texplain.nim(70, 6) RegularConcept: undeclared field: 'bar'
 texplain.nim(70, 6) RegularConcept: undeclared field: '.'
 texplain.nim(70, 6) RegularConcept: expression '.' cannot be called
-texplain.nim(69, 5) RegularConcept: type class predicate failed
-texplain.nim(73, 5) NestedConcept: type class predicate failed
+texplain.nim(69, 5) RegularConcept: concept predicate failed
+texplain.nim(73, 5) NestedConcept: concept predicate failed
 '''
   line: 119
   errormsg: "type mismatch: got (MatchingType)"
diff --git a/tests/concepts/tgraph.nim b/tests/concepts/tgraph.nim
index a0177a043..985f04a61 100644
--- a/tests/concepts/tgraph.nim
+++ b/tests/concepts/tgraph.nim
@@ -1,29 +1,34 @@
-discard """
-  output: '''XY is Node
-MyGraph is Graph'''
-"""
 # bug #3452
 import math
 
 type
-    Node* = concept n
-        `==`(n, n) is bool
+  Node* = concept n
+    `==`(n, n) is bool
 
-    Graph* = concept g
-        var x: Node
-        distance(g, x, x) is float
+  Graph1* = concept g
+    type N = Node
+    distance(g, N, N) is float
 
-    XY* = tuple[x, y: int]
+  Graph2 = concept g
+    distance(g, Node, Node) is float
 
-    MyGraph* = object
-        points: seq[XY]
+  Graph3 = concept g
+    var x: Node
+    distance(g, x, x) is float
 
-if XY is Node:
-    echo "XY is Node"
+  XY* = tuple[x, y: int]
+
+  MyGraph* = object
+    points: seq[XY]
+
+static:
+  assert XY is Node
 
 proc distance*( g: MyGraph, a, b: XY): float =
-    sqrt( pow(float(a.x - b.x), 2) + pow(float(a.y - b.y), 2) )
+  sqrt( pow(float(a.x - b.x), 2) + pow(float(a.y - b.y), 2) )
 
-if MyGraph is Graph:
-    echo "MyGraph is Graph"
+static:
+  assert MyGraph is Graph1
+  assert MyGraph is Graph2
+  assert MyGraph is Graph3
 
diff --git a/tests/concepts/trandomvars.nim b/tests/concepts/trandomvars.nim
new file mode 100644
index 000000000..db41aa901
--- /dev/null
+++ b/tests/concepts/trandomvars.nim
@@ -0,0 +1,61 @@
+discard """
+output: '''
+true
+true
+true
+3
+18.0
+324.0
+'''
+"""
+
+type RNG = object
+
+proc random(rng: var RNG): float = 1.0
+
+type
+  RandomVar[A] = concept x
+    var rng: RNG
+    rng.sample(x) is A
+
+  Constant[A] = object
+    value: A
+
+  Uniform = object
+    a, b: float
+
+  ClosureVar[A] = proc(rng: var RNG): A
+
+proc sample[A](rng: var RNG, c: Constant[A]): A = c.value
+
+proc sample(rng: var RNG, u: Uniform): float = u.a + (u.b - u.a) * rng.random()
+
+proc sample[A](rng: var RNG, c: ClosureVar[A]): A = c(rng)
+
+proc constant[A](a: A): Constant[A] = Constant[A](value: a)
+
+proc uniform(a, b: float): Uniform = Uniform(a: a, b: b)
+
+proc lift1[A, B](f: proc(a: A): B, r: RandomVar[A]): ClosureVar[B] =
+  proc inner(rng: var RNG): B = f(rng.sample(r))
+
+  return inner
+
+when isMainModule:
+  proc sq(x: float): float = x * x
+
+  let
+    c = constant(3)
+    u = uniform(2, 18)
+    t = lift1(sq, u)
+
+  var rng: RNG
+
+  echo(c is RandomVar[int])
+  echo(u is RandomVar[float])
+  echo(t is RandomVar[float])
+
+  echo rng.sample(c)
+  echo rng.sample(u)
+  echo rng.sample(t)
+
diff --git a/tests/concepts/twrapconcept.nim b/tests/concepts/twrapconcept.nim
new file mode 100644
index 000000000..25a855e34
--- /dev/null
+++ b/tests/concepts/twrapconcept.nim
@@ -0,0 +1,22 @@
+discard """
+  errormsg: "type mismatch: got (string)"
+  line: 21
+  nimout: "twrapconcept.nim(11, 5) Foo: concept predicate failed"
+"""
+
+# https://github.com/nim-lang/Nim/issues/5127
+
+type
+  Foo = concept foo
+    foo.get is int
+  
+  FooWrap[F: Foo] = object
+    foo: F
+
+proc get(x: int): int = x
+
+proc wrap[F: Foo](foo: F): FooWrap[F] = FooWrap[F](foo: foo)
+
+let x = wrap(12)
+let y = wrap "string"
+
diff --git a/tests/errmsgs/tconceptconstraint.nim b/tests/errmsgs/tconceptconstraint.nim
new file mode 100644
index 000000000..c1f0b94eb
--- /dev/null
+++ b/tests/errmsgs/tconceptconstraint.nim
@@ -0,0 +1,21 @@
+discard """
+  errormsg: "cannot instantiate B"
+  line: 20
+  nimout: '''
+got: (type string)
+but expected: (T: A)
+'''
+"""
+
+type
+  A = concept c
+    advance(c)
+  
+  B[T: A] = object
+    child: ref B[T]
+
+proc advance(x: int): int = x + 1
+
+var a: B[int]
+var b: B[string]
+
diff --git a/tests/errmsgs/tgenericconstraint.nim b/tests/errmsgs/tgenericconstraint.nim
new file mode 100644
index 000000000..9129d257b
--- /dev/null
+++ b/tests/errmsgs/tgenericconstraint.nim
@@ -0,0 +1,15 @@
+discard """
+  errormsg: "cannot instantiate B"
+  line: 14
+  nimout: '''
+got: (type int)
+but expected: (T: string or float)
+'''
+"""
+
+type
+  B[T: string|float] = object
+    child: ref B[T]
+
+var b: B[int]
+
diff --git a/tests/fields/timplicitfieldswithpartial.nim b/tests/fields/timplicitfieldswithpartial.nim
new file mode 100644
index 000000000..996912a1a
--- /dev/null
+++ b/tests/fields/timplicitfieldswithpartial.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''(foo: 38, other: string here)
+43'''
+"""
+
+type
+  Base = ref object of RootObj
+  Foo {.partial.} = ref object of Base
+
+proc my(f: Foo) =
+  #var f.next = f
+  let f.foo = 38
+  let f.other = "string here"
+  echo f[]
+  echo f.foo + 5
+
+var g: Foo
+new(g)
+my(g)
diff --git a/tests/generics/tfakedependenttypes.nim b/tests/generics/tfakedependenttypes.nim
new file mode 100644
index 000000000..cd4be806c
--- /dev/null
+++ b/tests/generics/tfakedependenttypes.nim
@@ -0,0 +1,61 @@
+discard """
+output: '''
+U[3]
+U[(f: 3)]
+U[[3]]
+'''
+"""
+
+# https://github.com/nim-lang/Nim/issues/5106
+
+import typetraits
+
+block:
+  type T = distinct int
+
+  proc `+`(a, b: T): T =
+    T(int(a) + int(b))
+
+  type U[F: static[T]] = distinct int
+
+  proc `+`[P1, P2: static[T]](a: U[P1], b: U[P2]): U[P1 + P2] =
+    U[P1 + P2](int(a) + int(b))
+
+  var a = U[T(1)](1)
+  var b = U[T(2)](2)
+  var c = a + b
+  echo c.type.name
+  
+block:
+  type T = object
+    f: int
+
+  proc `+`(a, b: T): T =
+    T(f: a.f + b.f)
+
+  type U[F: static[T]] = distinct int
+
+  proc `+`[P1, P2: static[T]](a: U[P1], b: U[P2]): U[P1 + P2] =
+    U[P1 + P2](int(a) + int(b))
+
+  var a = U[T(f: 1)](1)
+  var b = U[T(f: 2)](2)
+  var c = a + b
+  echo c.type.name
+
+block:
+  type T = distinct array[0..0, int]
+
+  proc `+`(a, b: T): T =
+    T([array[0..0, int](a)[0] + array[0..0, int](b)[0]])
+
+  type U[F: static[T]] = distinct int
+
+  proc `+`[P1, P2: static[T]](a: U[P1], b: U[P2]): U[P1 + P2] =
+    U[P1 + P2](int(a) + int(b))
+
+  var a = U[T([1])](1)
+  var b = U[T([2])](2)
+  var c = a + b
+  echo c.type.name
+
diff --git a/tests/generics/tgenericsdefaultvalues.nim b/tests/generics/tgenericsdefaultvalues.nim
new file mode 100644
index 000000000..2604c1031
--- /dev/null
+++ b/tests/generics/tgenericsdefaultvalues.nim
@@ -0,0 +1,14 @@
+discard """
+output: "12"
+"""
+
+# https://github.com/nim-lang/Nim/issues/5864
+
+proc defaultStatic(s: openarray, N: static[int] = 1): int = N
+proc defaultGeneric[T](a: T = 2): int = a
+
+let a = [1, 2, 3, 4].defaultStatic()
+let b = defaultGeneric()
+
+echo a, b
+
diff --git a/tests/generics/tproctypecache_falsepositive.nim b/tests/generics/tproctypecache_falsepositive.nim
new file mode 100644
index 000000000..4f24a1fc8
--- /dev/null
+++ b/tests/generics/tproctypecache_falsepositive.nim
@@ -0,0 +1,17 @@
+
+import asyncdispatch
+
+type
+  Callback = proc() {.closure, gcsafe.}
+  GameState = ref object
+    playerChangeHandlers: seq[Callback]
+
+#proc dummy() =
+#  var x = newSeq[proc() {.cdecl, gcsafe.}]()
+
+proc newGameState(): GameState =
+  result = GameState(
+    playerChangeHandlers: newSeq[Callback]() # this fails
+  )
+
+#dummy()
diff --git a/tests/generics/treentranttypes.nim b/tests/generics/treentranttypes.nim
new file mode 100644
index 000000000..9b4774e9b
--- /dev/null
+++ b/tests/generics/treentranttypes.nim
@@ -0,0 +1,111 @@
+discard """
+output: '''
+(Field0: 10, Field1: (Field0: test, Field1: 1.2))
+3x3 Matrix [[0.0, 2.0, 3.0], [2.0, 0.0, 5.0], [2.0, 0.0, 5.0]]
+
+2x3 Matrix [[0.0, 2.0, 3.0], [2.0, 0.0, 5.0]]
+
+2x3 Literal [[0.0, 2.0, 3.0], [2.0, 0.0, 5.0]]
+
+2x3 Matrix [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
+
+2x2 ArrayArray[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
+
+2x3 ArrayVector[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
+
+2x3 VectorVector [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
+
+2x3 VectorArray [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
+
+@[1, 2]
+@[1, 2]
+@[1, 2]@[3, 4]
+@[1, 2]@[3, 4]
+'''
+"""
+
+# https://github.com/nim-lang/Nim/issues/5962
+
+type
+  ArrayLike[A, B] = (A, B)
+  VectorLike*[SIZE, T] = ArrayLike[SIZE, T]
+  MatrixLike*[M, N, T] = VectorLike[M, VectorLike[N, T]]
+
+proc tupleTest =
+  let m: MatrixLike[int, string, float] = (10, ("test", 1.2))
+  echo m
+
+tupleTest()
+
+type
+  Vector*[K: static[int], T] =
+    array[K, T]
+
+  Matrix*[M: static[int]; N: static[int]; T] =
+    Vector[M, Vector[N, T]]
+  
+proc arrayTest =
+  # every kind of square matrix works just fine
+  let mat_good: Matrix[3, 3, float] = [[0.0, 2.0, 3.0],
+                                       [2.0, 0.0, 5.0],
+                                       [2.0, 0.0, 5.0]]
+  echo "3x3 Matrix ", repr(mat_good)
+
+  # this does not work with explicit type signature (the matrix seems to always think it is NxN instead)
+  let mat_fail: Matrix[2, 3, float] = [[0.0, 2.0, 3.0],
+                                       [2.0, 0.0, 5.0]]
+  echo "2x3 Matrix ", repr(mat_fail)
+
+  # this literal seems to work just fine
+  let mat_also_good = [[0.0, 2.0, 3.0],
+                       [2.0, 0.0, 5.0]]
+
+  echo "2x3 Literal ", repr(mat_also_good)
+
+  # but making a named type out of this leads to pretty nasty runtime behavior
+  var mat_fail_runtime: Matrix[2, 3, float]
+  echo "2x3 Matrix ", repr(mat_fail_runtime)
+
+  # cutting out the matrix type middle man seems to solve our problem
+  var mat_ok_runtime: array[2, array[3, float]]
+  echo "2x2 ArrayArray", repr(mat_ok_runtime)
+
+  # this is fine too
+  var mat_ok_runtime_2: array[2, Vector[3, float]]
+  echo "2x3 ArrayVector", repr(mat_ok_runtime_2)
+
+  # here we are in trouble again
+  var mat_fail_runtime_2: Vector[2, Vector[3, float]]
+  echo "2x3 VectorVector ", repr(mat_fail_runtime_2)
+
+  # and here we are fine again
+  var mat_ok_runtime_3: Vector[2, array[3, float]]
+  echo "2x3 VectorArray ", repr(mat_ok_runtime_3)
+
+arrayTest()
+
+# https://github.com/nim-lang/Nim/issues/5756
+
+type
+  Vec*[N : static[int]] = object
+    arr*: array[N, int32]
+
+  Mat*[M,N: static[int]] = object
+    arr*: array[M, Vec[N]]
+
+proc vec2*(x,y:int32) : Vec[2] =
+  result.arr = [x,y]
+
+proc mat2*(a,b: Vec[2]): Mat[2,2] =
+  result.arr = [a,b]
+
+const a = vec2(1,2)
+echo @(a.arr)
+let x = a
+echo @(x.arr)
+
+const b = mat2(vec2(1, 2), vec2(3, 4))
+echo @(b.arr[0].arr), @(b.arr[1].arr)
+let y = b
+echo @(y.arr[0].arr), @(y.arr[1].arr)
+
diff --git a/tests/js/tjshello.nim b/tests/js/tjshello.nim
new file mode 100644
index 000000000..19e0b90ae
--- /dev/null
+++ b/tests/js/tjshello.nim
@@ -0,0 +1,10 @@
+discard """
+  output: "Hello World"
+  maxcodesize: 1000
+  ccodecheck: "!@'function'"
+"""
+
+import jsconsole
+
+console.log "Hello World"
+
diff --git a/tests/js/tseqops.nim b/tests/js/tseqops.nim
new file mode 100644
index 000000000..d10e1ca6a
--- /dev/null
+++ b/tests/js/tseqops.nim
@@ -0,0 +1,51 @@
+discard """
+  output: '''(x: 0, y: 0)
+(x: 5, y: 0)
+@[(x: 2, y: 4), (x: 4, y: 5), (x: 4, y: 5)]
+@[(a: 3, b: 3), (a: 1, b: 1), (a: 2, b: 2)]
+'''
+"""
+
+# bug #4139
+
+type
+  TestO = object
+    x, y: int
+
+proc onLoad() =
+  var test: seq[TestO] = @[]
+  var foo = TestO(x: 0, y: 0)
+  test.add(foo)
+  foo.x = 5
+  echo(test[0])
+  echo foo
+
+onLoad()
+
+# 'setLen' bug (part of bug #5933)
+type MyObj = object
+  x: cstring
+  y: int
+
+proc foo(x: var seq[MyObj]) =
+  let L = x.len
+  x.setLen L + 1
+  x[L] = x[1]
+
+var s = @[MyObj(x: "2", y: 4), MyObj(x: "4", y: 5)]
+foo(s)
+echo s
+
+# bug  #5933
+import sequtils
+
+type
+  Test = object
+    a: cstring
+    b: int
+
+var test = @[Test(a: "1", b: 1), Test(a: "2", b: 2)]
+
+test.insert(@[Test(a: "3", b: 3)], 0)
+
+echo test
diff --git a/tests/macros/tnewlit.nim b/tests/macros/tnewlit.nim
new file mode 100644
index 000000000..69245d076
--- /dev/null
+++ b/tests/macros/tnewlit.nim
@@ -0,0 +1,140 @@
+import macros
+
+type
+  MyType = object
+    a : int
+    b : string
+
+macro test_newLit_MyType: untyped =
+  let mt = MyType(a: 123, b:"foobar")
+  result = newLit(mt)
+
+doAssert test_newLit_MyType == MyType(a: 123, b:"foobar")
+
+macro test_newLit_array: untyped =
+  let arr = [1,2,3,4,5]
+  result = newLit(arr)
+
+doAssert test_newLit_array == [1,2,3,4,5]
+
+macro test_newLit_seq_int: untyped =
+  let s: seq[int] = @[1,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[int] = test_newLit_seq_int
+  doAssert tmp == @[1,2,3,4,5]
+
+macro test_newLit_seq_int8: untyped =
+  let s: seq[int8] = @[1'i8,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[int8] = test_newLit_seq_int8
+  doAssert tmp == @[1'i8,2,3,4,5]
+
+macro test_newLit_seq_int16: untyped =
+  let s: seq[int16] = @[1'i16,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[int16] = test_newLit_seq_int16
+  doAssert tmp == @[1'i16,2,3,4,5]
+
+macro test_newLit_seq_int32: untyped =
+  let s: seq[int32] = @[1'i32,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[int32] = test_newLit_seq_int32
+  doAssert tmp == @[1'i32,2,3,4,5]
+
+macro test_newLit_seq_int64: untyped =
+  let s: seq[int64] = @[1'i64,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[int64] = test_newLit_seq_int64
+  doAssert tmp == @[1'i64,2,3,4,5]
+
+macro test_newLit_seq_uint: untyped =
+  let s: seq[uint] = @[1u,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[uint] = test_newLit_seq_uint
+  doAssert tmp == @[1u,2,3,4,5]
+
+macro test_newLit_seq_uint8: untyped =
+  let s: seq[uint8] = @[1'u8,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[uint8] = test_newLit_seq_uint8
+  doAssert tmp == @[1'u8,2,3,4,5]
+
+macro test_newLit_seq_uint16: untyped =
+  let s: seq[uint16] = @[1'u16,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[uint16] = test_newLit_seq_uint16
+  doAssert tmp == @[1'u16,2,3,4,5]
+
+macro test_newLit_seq_uint32: untyped =
+  let s: seq[uint32] = @[1'u32,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[uint32] = test_newLit_seq_uint32
+  doAssert tmp == @[1'u32,2,3,4,5]
+
+macro test_newLit_seq_uint64: untyped =
+  let s: seq[uint64] = @[1'u64,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[uint64] = test_newLit_seq_uint64
+  doAssert tmp == @[1'u64,2,3,4,5]
+
+macro test_newLit_seq_float: untyped =
+  let s: seq[float] = @[1.0, 2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[float] = test_newLit_seq_float
+  doAssert tmp == @[1.0, 2,3,4,5]
+
+macro test_newLit_seq_float32: untyped =
+  let s: seq[float32] = @[1.0'f32, 2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[float32] = test_newLit_seq_float32
+  doAssert tmp == @[1.0'f32, 2,3,4,5]
+
+macro test_newLit_seq_float64: untyped =
+  let s: seq[float64] = @[1.0'f64, 2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[float64] = test_newLit_seq_float64
+  doAssert tmp == @[1.0'f64, 2,3,4,5]
+
+macro test_newLit_tuple: untyped =
+  let tup: tuple[a:int,b:string] = (a: 123, b: "223")
+  result = newLit(tup)
+
+doAssert test_newLit_tuple == (a: 123, b: "223")
+
+type
+  ComposedType = object
+    mt: MyType
+    arr: array[4,int]
+    data: seq[byte]
+
+macro test_newLit_ComposedType: untyped =
+  let ct = ComposedType(mt: MyType(a: 123, b:"abc"), arr: [1,2,3,4], data: @[1.byte, 3, 7, 127])
+  result = newLit(ct)
+
+doAssert test_newLit_ComposedType == ComposedType(mt: MyType(a: 123, b:"abc"), arr: [1,2,3,4], data: @[1.byte, 3, 7, 127])
diff --git a/tests/macros/tnodecompare.nim b/tests/macros/tnodecompare.nim
index 3870c7559..b9cf7df48 100644
--- a/tests/macros/tnodecompare.nim
+++ b/tests/macros/tnodecompare.nim
@@ -1,33 +1,33 @@
-discard """
-output: '''true
-false
-true
-false
-true
-false
-true
-false'''
-"""
-
 import macros
 
+static:
+  let nodeA = newCommentStmtNode("this is a comment")
+  doAssert nodeA.repr == "## this is a comment"
+  doAssert nodeA.strVal == "this is a comment"
+  doAssert $nodeA == "this is a comment"
+
+  let nodeB = newCommentStmtNode("this is a comment")
+  doAssert nodeA == nodeB
+  nodeB.strVal = "this is a different comment"
+  doAssert nodeA != nodeB
+
 macro test(a: typed, b: typed): expr =
   newLit(a == b)
 
-echo test(1, 1)
-echo test(1, 2)
+doAssert test(1, 1) == true
+doAssert test(1, 2) == false
 
 type
   Obj = object of RootObj
   Other = object of RootObj
 
-echo test(Obj, Obj)
-echo test(Obj, Other)
+doAssert test(Obj, Obj) == true
+doAssert test(Obj, Other) == false
 
 var a, b: int
 
-echo test(a, a)
-echo test(a, b)
+doAssert test(a, a) == true
+doAssert test(a, b) == false
 
 macro test2: expr =
   newLit(bindSym"Obj" == bindSym"Obj")
@@ -35,5 +35,5 @@ macro test2: expr =
 macro test3: expr =
   newLit(bindSym"Obj" == bindSym"Other")
 
-echo test2()
-echo test3()
+doAssert test2() == true
+doAssert test3() == false
diff --git a/tests/metatype/tmatrix4.nim b/tests/metatype/tmatrix4.nim
new file mode 100644
index 000000000..207d76fed
--- /dev/null
+++ b/tests/metatype/tmatrix4.nim
@@ -0,0 +1,39 @@
+import math
+
+type
+  TMatrix*[T; R, C: static[int]] = array[R, array[C, T]] ## Row major matrix type.
+  TMat4* = TMatrix[float32, 4, 4]
+  TVector*[T; C: static[int]] = array[C, T]
+  TVec4* = TVector[float32, 4]
+
+template row*[T; R, C: static[int]](m: TMatrix[T, R, C], rowidx: range[0..R-1]): TVector[T, R] =
+  m[rowidx]
+
+proc col*[T; R, C: static[int]](m: TMatrix[T, R, C], colidx: range[0..C-1]): TVector[T, C] {.noSideEffect.} =
+  for i in low(m)..high(m):
+    result[i] = m[i][colidx]
+
+proc dot(lhs, rhs: TVector): float32 =
+  for i in low(rhs)..high(rhs):
+    result += lhs[i] * rhs[i]
+
+proc `*`*[T; R, N, C: static[int]](a: TMatrix[T, R, N], b: TMatrix[T, N, C]): TMatrix[T, R, C] {.noSideEffect.} =
+  for i in low(a)..high(a):
+    for j in low(a[i])..high(a[i]):
+      result[i][j] = dot(a.row(i), b.col(j))
+
+proc translate*(v: TVec4): TMat4 {.noSideEffect.} =
+  result = [[1f32, 0f32, 0f32, 0f32],
+            [0f32, 1f32, 0f32, 0f32],
+            [0f32, 0f32, 1f32, 0f32],
+            [v[0], v[1], v[2], 1f32]]
+
+proc rotatex*(angle: float): TMat4 =
+  result = [[1f32,          0f32,           0f32,           0f32],
+            [0f32, cos(angle).float32, sin(angle).float32,  0f32],
+            [0f32, -sin(angle).float32, cos(angle).float32, 0f32],
+            [0f32,          0f32,           0f32,           1f32]]
+
+proc orbitxAround(point: TVec4, angle: float): TMat4 =
+  result = translate(point)*rotatex(angle)*translate(point)
+
diff --git a/tests/metatype/tstaticparams.nim b/tests/metatype/tstaticparams.nim
index 11653e563..69b62e4a6 100644
--- a/tests/metatype/tstaticparams.nim
+++ b/tests/metatype/tstaticparams.nim
@@ -1,6 +1,6 @@
 discard """
   file: "tstaticparams.nim"
-  output: "abracadabra\ntest\n3\n15\n4\n2\nfloat\n3\nfloat\nyin\nyang"
+  output: "abracadabra\ntest\n3\n15\n4\n2\nfloat\n3\nfloat\nyin\nyang\n2\n4\n4\n2\n3"
 """
 
 type
@@ -140,3 +140,36 @@ dontBind1 bb_2
 dontBind2 bb_1
 dontBind2 bb_2
 
+# https://github.com/nim-lang/Nim/issues/4524 
+const
+  size* = 2
+
+proc arraySize[N: static[int]](A: array[N, int]): int =
+  result = A.high - A.low + 1
+
+var A: array[size, int] = [1, 2]
+echo arraySize(A)
+
+# https://github.com/nim-lang/Nim/issues/3153
+
+proc outSize1[M: static[int], A](xs: array[M, A]): int = M
+echo outSize1([1, 2, 3, 4])
+
+type
+  Arr[N: static[int], A] = array[N, A]
+
+proc outSize2[M: static[int], A](xs: Arr[M, A]): int = M
+echo outSize2([1, 2, 3, 4]) # 4
+
+echo outSize2([
+  [1, 2, 3],
+  [4, 5, 6]
+]) # 2
+
+proc inSize[M, N: static[int]](xs: Arr[M, Arr[N, int]]): int = N
+
+echo inSize([
+  [1, 2, 3],
+  [4, 5, 6]
+])
+
diff --git a/tests/metatype/tstaticvector.nim b/tests/metatype/tstaticvector.nim
index 69ee0e935..1a7bdeafe 100644
--- a/tests/metatype/tstaticvector.nim
+++ b/tests/metatype/tstaticvector.nim
@@ -2,7 +2,9 @@ discard """
   output: '''0
 0
 2
-100'''
+100
+30.0 [data = [2.0]]
+'''
 """
 
 type
@@ -16,13 +18,12 @@ type
 proc foo*[N, T](a: StaticVector[N, T]): T = 0.T
 proc foobar*[N, T](a, b: StaticVector[N, T]): T = 0.T
 
-
 var a: StaticVector[3, int]
 
 echo foo(a) # OK
 echo foobar(a, a) # <--- hangs compiler
 
-# bug #3112
+# https://github.com/nim-lang/Nim/issues/3112
 
 type
   Vector[N: static[int]] = array[N, float64]
@@ -30,10 +31,45 @@ type
     a: Vector[Na]
     b: Vector[Nb]
 
-when isMainModule:
-  var v: TwoVectors[2, 100]
-  echo v[0].len
-  echo v[1].len
-  #let xx = 50
-  v[1][50] = 0.0
+var v: TwoVectors[2, 100]
+echo v[0].len
+echo v[1].len
+#let xx = 50
+v[1][50] = 0.0
+
+# https://github.com/nim-lang/Nim/issues/1051
+
+type
+  TMatrix[N,M: static[int], T] = object
+    data: array[0..M*N-1, T]
+
+  TMat4f = TMatrix[4,4,float32]
+  TVec3f = TMatrix[1,3,float32]
+  TVec4f = TMatrix[1,4,float32]
+
+  TVec[N: static[int]; T] = TMatrix[1,N,T]
+
+proc dot*(a, b: TVec): TVec.T =
+  #assert(a.data.len == b.data.len)
+  for i in 1..a.data.len:
+    result += a.data[i-1] * b.data[i-1]
+
+proc row*(a: TMatrix; i: int): auto =
+  result = TVec[TMatrix.M, TMatrix.T]()
+  for idx in 1 .. TMatrix.M:
+    result.data[idx-1] = a.data[(TMatrix.N * (idx-1)) + (i-1)]
+
+proc col*(a: TMatrix; j: int): auto =
+  result = TVec[TMatrix.N, TMatrix.T]()
+  for idx in 0 .. <TMatrix.N:
+    result.data[idx] = a.data[(TMatrix.N * (idx)) + (j-1)]
+
+proc mul*(a: TMat4f; b: TMat4f): TMat4f =
+  for i in 1..4:
+    for j in 1..4:
+      result.data[(4 * (j-1)) + (i-1)] = dot(row(a,i), col(b,j))
+
+var test = TVec4f(data: [1.0'f32, 2.0'f32, 3.0'f32, 4.0'f32])
+
+echo dot(test,test), " ", repr(col(test, 2))
 
diff --git a/tests/misc/tcast.nim b/tests/misc/tcast.nim
new file mode 100644
index 000000000..4e27040fb
--- /dev/null
+++ b/tests/misc/tcast.nim
@@ -0,0 +1,23 @@
+discard """
+  output: '''
+Hello World
+Hello World'''
+"""
+type MyProc = proc() {.cdecl.}
+type MyProc2 = proc() {.nimcall.}
+type MyProc3 = proc() #{.closure.} is implicit
+
+proc testProc()  = echo "Hello World"
+
+proc callPointer(p: pointer) =
+  # can cast to proc(){.cdecl.}
+  let ffunc0 = cast[MyProc](p)
+  # can cast to proc(){.nimcall.}
+  let ffunc1 = cast[MyProc2](p)
+  # cannot cast to proc(){.closure.}
+  doAssert(not compiles(cast[MyProc3](p)))
+
+  ffunc0()
+  ffunc1()
+
+callPointer(cast[pointer](testProc))
diff --git a/tests/misc/tparseopt.nim b/tests/misc/tparseopt.nim
new file mode 100644
index 000000000..1f8375dfd
--- /dev/null
+++ b/tests/misc/tparseopt.nim
@@ -0,0 +1,57 @@
+discard """
+  file: "tparseopt.nim"
+  output: '''
+parseopt
+first round
+kind: cmdLongOption	key:val  --  left:
+second round
+kind: cmdLongOption	key:val  --  left:
+kind: cmdLongOption	key:val  --  debug:3
+kind: cmdShortOption	key:val  --  l:4
+kind: cmdShortOption	key:val  --  r:2
+parseopt2
+first round
+kind: cmdLongOption	key:val  --  left:
+second round
+kind: cmdLongOption	key:val  --  left:
+kind: cmdLongOption	key:val  --  debug:3
+kind: cmdShortOption	key:val  --  l:4
+kind: cmdShortOption	key:val  --  r:2'''
+"""
+from parseopt import nil
+from parseopt2 import nil
+
+
+block:
+    echo "parseopt"
+    for kind, key, val in parseopt.getopt():
+      echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
+
+    # pass custom cmdline arguments
+    echo "first round"
+    var argv = "--left --debug:3 -l=4 -r:2"
+    var p = parseopt.initOptParser(argv)
+    for kind, key, val in parseopt.getopt(p):
+      echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
+      break
+    # reset getopt iterator and check arguments are returned correctly.
+    echo "second round"
+    for kind, key, val in parseopt.getopt(p):
+      echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
+
+block:
+    echo "parseopt2"
+    for kind, key, val in parseopt2.getopt():
+      echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
+
+    # pass custom cmdline arguments
+    echo "first round"
+    var argv: seq[string] = @["--left", "--debug:3", "-l=4", "-r:2"]
+    var p = parseopt2.initOptParser(argv)
+    for kind, key, val in parseopt2.getopt(p):
+      echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
+      break
+    # reset getopt iterator and check arguments are returned correctly.
+    echo "second round"
+    for kind, key, val in parseopt2.getopt(p):
+      echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
diff --git a/tests/modules/tmismatchedvisibility.nim b/tests/modules/tmismatchedvisibility.nim
index 325c729c0..91b639a27 100644
--- a/tests/modules/tmismatchedvisibility.nim
+++ b/tests/modules/tmismatchedvisibility.nim
@@ -1,6 +1,6 @@
 discard """
   line: 8
-  errormsg: "public implementation 'tmismatchedvisibility.foo(a: int)' has non-public forward declaration in "
+  errormsg: "public implementation 'tmismatchedvisibility.foo(a: int)[declared in tmismatchedvisibility.nim(6,5)]' has non-public forward declaration in "
 """
 
 proc foo(a: int): int
diff --git a/tests/overload/tstaticoverload.nim b/tests/overload/tstaticoverload.nim
new file mode 100644
index 000000000..33ca49e56
--- /dev/null
+++ b/tests/overload/tstaticoverload.nim
@@ -0,0 +1,30 @@
+discard """
+output: '''
+dynamic: let
+dynamic: var
+static: const
+static: literal
+static: constant folding
+static: static string
+'''
+"""
+
+proc foo(s: string) =
+  echo "dynamic: ", s
+
+proc foo(s: static[string]) =
+  echo "static: ", s
+
+let l = "let"
+var v = "var"
+const c = "const"
+
+type staticString = static[string]
+
+foo(l)
+foo(v)
+foo(c)
+foo("literal")
+foo("constant" & " " & "folding")
+foo(staticString("static string"))
+
diff --git a/tests/pragmas/tused.nim b/tests/pragmas/tused.nim
index 4a317f874..389863aef 100644
--- a/tests/pragmas/tused.nim
+++ b/tests/pragmas/tused.nim
@@ -1,7 +1,7 @@
 discard """
   nimout: '''
 compile start
-tused.nim(15, 8) Hint: 'tused.echoSub(a: int, b: int)' is declared but not used [XDeclaredButNotUsed]
+tused.nim(15, 8) Hint: 'tused.echoSub(a: int, b: int)[declared in tused.nim(15,7)]' is declared but not used [XDeclaredButNotUsed]
 compile end'''
   output: "8\n8"
 """
diff --git a/tests/statictypes/t3784.nim b/tests/statictypes/t3784.nim
new file mode 100644
index 000000000..3414d9802
--- /dev/null
+++ b/tests/statictypes/t3784.nim
@@ -0,0 +1,20 @@
+discard """
+output: "T[1, 1]"
+"""
+
+# https://github.com/nim-lang/Nim/issues/3784
+
+import typetraits
+
+type
+  S[N: static[int]] = object
+  T[A,B: static[int]] = object
+  
+  C = S[1]
+
+var
+  x: T[1,1]
+  y: T[C.N, C.N]
+
+echo y.type.name
+
diff --git a/tests/statictypes/texplicitprocparams.nim b/tests/statictypes/texplicitprocparams.nim
new file mode 100644
index 000000000..d1e717dbf
--- /dev/null
+++ b/tests/statictypes/texplicitprocparams.nim
@@ -0,0 +1,19 @@
+discard """
+output: '''
+(x: 100)
+5
+'''
+"""
+
+type
+  OdArray*[As: static[int], T] = object
+    x: int
+
+proc initOdArray*[As: static[int], T](len: int): OdArray[As, T] =
+  result.x = len
+
+echo initOdArray[10, int](100)
+
+proc doStatic[N: static[int]](): int = N
+echo doStatic[5]()
+
diff --git a/tests/statictypes/tpassthruarith.nim b/tests/statictypes/tpassthruarith.nim
new file mode 100644
index 000000000..90fc7824c
--- /dev/null
+++ b/tests/statictypes/tpassthruarith.nim
@@ -0,0 +1,54 @@
+discard """
+output: '''
+[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
+
+[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+
+[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+
+[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+
+[1, 2, 3, 4]
+'''
+"""
+
+# https://github.com/nim-lang/Nim/issues/4880
+
+proc `^^`(x: int): int = x * 2
+
+type
+  Foo[x: static[int]] = array[x, int]
+  Bar[a, b: static[int]] = array[b, Foo[^^a]]
+
+var x: Bar[2, 3]
+echo repr(x)
+
+# https://github.com/nim-lang/Nim/issues/2730
+
+type
+  Matrix[M,N: static[int]] = distinct array[0..(M*N - 1), int]
+
+proc bigger[M,N](m: Matrix[M,N]): Matrix[(M * N) div 8, (M * N)] =
+  discard
+
+proc bigger2[M,N](m: Matrix[M,N]): Matrix[M * 2, N * 2] =
+  discard
+
+var m : Matrix[4, 4]
+var n = bigger(m)
+var o = bigger2(m)
+
+echo repr(m)
+echo repr(n)
+echo repr(o)
+
+type
+  Vect[N: static[int], A] = array[N, A]
+
+proc push[N: static[int], A](a: Vect[N, A], x: A): Vect[N + 1, A] =
+  for n in 0 .. < N:
+    result[n] = a[n]
+  result[N] = x
+
+echo repr(push([1, 2, 3], 4))
+
diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim
index 538582ba8..581308a7e 100644
--- a/tests/stdlib/tmath.nim
+++ b/tests/stdlib/tmath.nim
@@ -1,4 +1,15 @@
-import math, random
+discard """
+  action: run
+  output: '''[Suite] random int
+
+[Suite] random float
+
+[Suite] ^
+
+'''
+"""
+
+import math, random, os
 import unittest
 import sets
 
@@ -26,6 +37,7 @@ suite "random int":
   test "randomize() again gives new numbers":
     randomize()
     var rand1 = random(1000000)
+    os.sleep(200)
     randomize()
     var rand2 = random(1000000)
     check rand1 != rand2
@@ -55,7 +67,16 @@ suite "random float":
   test "randomize() again gives new numbers":
     randomize()
     var rand1:float = random(1000000.0)
+    os.sleep(200)
     randomize()
     var rand2:float = random(1000000.0)
     check rand1 != rand2
 
+suite "^":
+  test "compiles for valid types":
+    check: compiles(5 ^ 2)
+    check: compiles(5.5 ^ 2)
+    check: compiles(5.5 ^ 2.int8)
+    check: compiles(5.5 ^ 2.uint)
+    check: compiles(5.5 ^ 2.uint8)
+    check: not compiles(5.5 ^ 2.2)
\ No newline at end of file
diff --git a/tests/stdlib/torderedtable.nim b/tests/stdlib/torderedtable.nim
new file mode 100644
index 000000000..91a916930
--- /dev/null
+++ b/tests/stdlib/torderedtable.nim
@@ -0,0 +1,18 @@
+import tables, random
+var t = initOrderedTable[int,string]()
+
+# this tests issue #5917
+var data = newSeq[int]()
+for i in 0..<1000:
+  var x = random(1000)
+  if x notin t: data.add(x)
+  t[x] = "meh"
+
+# this checks that keys are re-inserted
+# in order when table is enlarged.
+var i = 0
+for k, v in t:
+  doAssert(k == data[i])
+  doAssert(v == "meh")
+  inc(i)
+
diff --git a/tests/testament/specs.nim b/tests/testament/specs.nim
index ab24acc70..ed435465a 100644
--- a/tests/testament/specs.nim
+++ b/tests/testament/specs.nim
@@ -52,6 +52,7 @@ type
     exitCode*: int
     msg*: string
     ccodeCheck*: string
+    maxCodeSize*: int
     err*: TResultEnum
     substr*, sortoutput*: bool
     targets*: set[TTarget]
@@ -109,6 +110,7 @@ proc specDefaults*(result: var TSpec) =
   result.tfile = ""
   result.tline = 0
   result.tcolumn = 0
+  result.maxCodeSize = 0
 
 proc parseTargets*(value: string): set[TTarget] =
   for v in value.normalize.split:
@@ -180,6 +182,7 @@ proc parseSpec*(filename: string): TSpec =
       else:
         result.cmd = e.value
     of "ccodecheck": result.ccodeCheck = e.value
+    of "maxcodesize": discard parseInt(e.value, result.maxCodeSize)
     of "target", "targets":
       for v in e.value.normalize.split:
         case v
diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim
index 0f74de013..b83eb668a 100644
--- a/tests/testament/tester.nim
+++ b/tests/testament/tester.nim
@@ -212,20 +212,31 @@ proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest) =
 proc generatedFile(path, name: string, target: TTarget): string =
   let ext = targetToExt[target]
   result = path / "nimcache" /
-    (if target == targetJS: path.splitPath.tail & "_" else: "compiler_") &
+    (if target == targetJS: "" else: "compiler_") &
     name.changeFileExt(ext)
 
-proc codegenCheck(test: TTest, check: string, given: var TSpec) =
+proc needsCodegenCheck(spec: TSpec): bool =
+  result = spec.maxCodeSize > 0 or spec.ccodeCheck.len > 0
+
+proc codegenCheck(test: TTest, spec: TSpec, expectedMsg: var string,
+                  given: var TSpec) =
   try:
     let (path, name, _) = test.name.splitFile
     let genFile = generatedFile(path, name, test.target)
     let contents = readFile(genFile).string
-    if check[0] == '\\':
-      # little hack to get 'match' support:
-      if not contents.match(check.peg):
+    let check = spec.ccodeCheck
+    if check.len > 0:
+      if check[0] == '\\':
+        # little hack to get 'match' support:
+        if not contents.match(check.peg):
+          given.err = reCodegenFailure
+      elif contents.find(check.peg) < 0:
         given.err = reCodegenFailure
-    elif contents.find(check.peg) < 0:
+      expectedMsg = check
+    if spec.maxCodeSize > 0 and contents.len > spec.maxCodeSize:
       given.err = reCodegenFailure
+      given.msg = "generated code size: " & $contents.len
+      expectedMsg = "max allowed size: " & $spec.maxCodeSize
   except ValueError:
     given.err = reInvalidPeg
     echo getCurrentExceptionMsg()
@@ -248,9 +259,8 @@ proc compilerOutputTests(test: TTest, given: var TSpec, expected: TSpec;
   var expectedmsg: string = ""
   var givenmsg: string = ""
   if given.err == reSuccess:
-    if expected.ccodeCheck.len > 0:
-      codegenCheck(test, expected.ccodeCheck, given)
-      expectedmsg = expected.ccodeCheck
+    if expected.needsCodegenCheck:
+      codegenCheck(test, expected, expectedmsg, given)
       givenmsg = given.msg
     if expected.nimout.len > 0:
       expectedmsg = expected.nimout
diff --git a/tests/typerel/ttypedesc_as_genericparam1.nim b/tests/typerel/ttypedesc_as_genericparam1.nim
index 677bf6fc8..88c0509b2 100644
--- a/tests/typerel/ttypedesc_as_genericparam1.nim
+++ b/tests/typerel/ttypedesc_as_genericparam1.nim
@@ -1,6 +1,6 @@
 discard """
   line: 6
-  errormsg: "type mismatch: got (typedesc[int])"
+  errormsg: "type mismatch: got (type int)"
 """
 # bug #3079, #1146
 echo repr(int)
diff --git a/tests/typerel/ttypenoval.nim b/tests/typerel/ttypenoval.nim
index d5b91fbca..eabca48f6 100644
--- a/tests/typerel/ttypenoval.nim
+++ b/tests/typerel/ttypenoval.nim
@@ -1,7 +1,7 @@
 discard """
   file: "ttypenoval.nim"
   line: 38
-  errormsg: "type mismatch: got (typedesc[int]) but expected 'int'"
+  errormsg: "type mismatch: got (type int) but expected 'int'"
 """
 
 # A min-heap.
diff --git a/tests/types/t1252.nim b/tests/types/t1252.nim
new file mode 100644
index 000000000..c6a12e9f7
--- /dev/null
+++ b/tests/types/t1252.nim
@@ -0,0 +1,12 @@
+discard """
+  output: '''true
+true
+true
+true
+'''
+"""
+
+echo float32 isnot float64
+echo float32 isnot float
+echo int32 isnot int64
+echo int32 isnot int
diff --git a/tests/types/thard_tyforward.nim b/tests/types/thard_tyforward.nim
index 7131cd64b..8f606a0f9 100644
--- a/tests/types/thard_tyforward.nim
+++ b/tests/types/thard_tyforward.nim
@@ -2,8 +2,8 @@ type
   Bar[T] = Foo[T, T]
   Baz[T] = proc (x: Foo[T, T])
   
-  GenericAlias[T] = Foo[T]
-  GenericAlias2[T] = Foo[Baz[T]]
+  GenericAlias[T] = Foo[T, T]
+  GenericAlias2[T] = Foo[Baz[T], T]
   
   Concrete1 = Foo[int, float]
   Concrete2 = proc(x: proc(a: Foo[int, float]))
diff --git a/tests/vm/tnimnode.nim b/tests/vm/tnimnode.nim
index cca03cd62..e5a41e3c2 100644
--- a/tests/vm/tnimnode.nim
+++ b/tests/vm/tnimnode.nim
@@ -72,3 +72,11 @@ static:
   echo "OK"
   
 
+static:
+  echo "testing creation of comment node"
+  var docComment: NimNode = newNimNode(nnkCommentStmt)
+  docComment.strVal = "This is a doc comment"
+
+  assertEq repr(docComment), "## This is a doc comment"
+
+  echo "OK"
diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim
index 67f5e2b33..e4568dc3a 100644
--- a/tools/niminst/niminst.nim
+++ b/tools/niminst/niminst.nim
@@ -679,11 +679,14 @@ RunProgram="tools\downloader.exe"
           if execShellCmd("7z a -sfx7zS2.sfx -t7z $1.exe $1" % proj) != 0:
             echo("External program failed (7z)")
       else:
-        if execShellCmd("XZ_OPT=-9 gtar Jcf $1.tar.xz $1 --exclude=.DS_Store" %
+        if execShellCmd("gtar cf $1.tar $1 --exclude=.DS_Store" %
                         proj) != 0:
           # try old 'tar' without --exclude feature:
-          if execShellCmd("XZ_OPT=-9 tar Jcf $1.tar.xz $1" % proj) != 0:
+          if execShellCmd("tar cf $1.tar $1" % proj) != 0:
             echo("External program failed")
+
+        if execShellCmd("xz -9f $1.tar" % proj) != 0:
+          echo("External program failed")
     finally:
       setCurrentDir(oldDir)