summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--changelog.md1
-rw-r--r--compiler/ccgcalls.nim5
-rw-r--r--compiler/ccgexprs.nim23
-rw-r--r--compiler/ccgstmts.nim13
-rw-r--r--compiler/cgendata.nim2
-rw-r--r--compiler/closureiters.nim81
-rw-r--r--compiler/lexer.nim2
-rw-r--r--compiler/pragmas.nim4
-rw-r--r--compiler/sigmatch.nim8
-rw-r--r--lib/packages/docutils/highlite.nim2
-rw-r--r--lib/pure/asyncmacro.nim111
-rw-r--r--lib/pure/collections/critbits.nim46
-rw-r--r--lib/pure/json.nim8
-rw-r--r--lib/pure/net.nim31
-rw-r--r--lib/pure/times.nim59
-rw-r--r--lib/system.nim2
-rw-r--r--lib/system/channels.nim2
-rw-r--r--tests/async/t7985.nim19
-rw-r--r--tests/async/tasync_traceback.nim26
-rw-r--r--tests/async/tasynctry.nim4
-rw-r--r--tests/async/tasynctry2.nim2
-rw-r--r--tests/collections/tcollections_to_string.nim6
-rw-r--r--tests/iter/tyieldintry.nim35
-rw-r--r--tests/lexer/thexlit.nim12
-rw-r--r--tests/lexer/thexrange.nim8
-rw-r--r--tests/lexer/tlexermisc.nim27
-rw-r--r--tests/stdlib/tnet.nim12
-rw-r--r--tests/system/tsystem_misc.nim39
-rw-r--r--tests/typerel/t4799.nim245
-rw-r--r--tests/typerel/t4799_1.nim20
-rw-r--r--tests/typerel/t4799_2.nim20
-rw-r--r--tests/typerel/t4799_3.nim20
32 files changed, 648 insertions, 247 deletions
diff --git a/changelog.md b/changelog.md
index 6fd12e62f..aae275c1c 100644
--- a/changelog.md
+++ b/changelog.md
@@ -85,6 +85,7 @@
 - The `terminal` module now exports additional procs for generating ANSI color
   codes as strings.
 - Added the parameter ``val`` for the ``CritBitTree[int].inc`` proc.
+- Added the parameter ``val`` for the ``CritBitTree[T].incl`` proc.
 - An exception raised from ``test`` block of ``unittest`` now shows its type in
   the error message
 - The proc ``tgamma`` was renamed to ``gamma``. ``tgamma`` is deprecated.
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 7d355db5f..22733f6ac 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -83,7 +83,7 @@ proc isInCurrentFrame(p: BProc, n: PNode): bool =
     result = isInCurrentFrame(p, n.sons[0])
   else: discard
 
-proc genIndexCheck(p: BProc; arr, idx: TLoc)
+proc genBoundsCheck(p: BProc; arr, a, b: TLoc)
 
 proc openArrayLoc(p: BProc, n: PNode): Rope =
   var a: TLoc
@@ -97,8 +97,7 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
     initLocExpr(p, q[3], c)
     # but first produce the required index checks:
     if optBoundsCheck in p.options:
-      genIndexCheck(p, a, b)
-      genIndexCheck(p, a, c)
+      genBoundsCheck(p, a, b, c)
     let ty = skipTypes(a.t, abstractVar+{tyPtr})
     case ty.kind
     of tyArray:
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 352402e0e..20b68b0aa 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -351,7 +351,9 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
     else:
       useStringh(p.module)
       linefmt(p, cpsStmts,
-           "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len_0);$n",
+           # bug #4799, keep the memcpy for a while
+           #"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len_0);$n",
+           "$1 = $2;$n",
            rdLoc(dest), rdLoc(src))
   of tySet:
     if mapType(ty) == ctArray:
@@ -873,21 +875,26 @@ proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) =
   putIntoDest(p, d, n,
               ropecg(p.module, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
 
-proc genIndexCheck(p: BProc; arr, idx: TLoc) =
+proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
   let ty = skipTypes(arr.t, abstractVarRange)
   case ty.kind
   of tyOpenArray, tyVarargs:
-    linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)) #raiseIndexError();$n",
-            rdLoc(idx), rdLoc(arr))
+    linefmt(p, cpsStmts,
+      "if ($2-$1 != -1 && " &
+      "((NU)($1) >= (NU)($3Len_0) || (NU)($2) >= (NU)($3Len_0))) #raiseIndexError();$n",
+      rdLoc(a), rdLoc(b), rdLoc(arr))
   of tyArray:
     let first = intLiteral(firstOrd(ty))
     if tfUncheckedArray notin ty.flags:
-      linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n",
-              rdCharLoc(idx), first, intLiteral(lastOrd(ty)))
+      linefmt(p, cpsStmts,
+        "if ($2-$1 != -1 && " &
+        "($2-$1 < -1 || $1 < $3 || $1 > $4 || $2 < $3 || $2 > $4)) #raiseIndexError();$n",
+        rdCharLoc(a), rdCharLoc(b), first, intLiteral(lastOrd(ty)))
   of tySequence, tyString:
     linefmt(p, cpsStmts,
-          "if (!$2 || (NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
-          rdLoc(idx), rdLoc(arr), lenField(p))
+      "if ($2-$1 != -1 && " &
+      "(!$3 || (NU)($1) >= (NU)($3->$4) || (NU)($2) >= (NU)($3->$4))) #raiseIndexError();$n",
+      rdLoc(a), rdLoc(b), rdLoc(arr), lenField(p))
   else: discard
 
 proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 91a3add70..f99ee9270 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -775,6 +775,13 @@ proc genCase(p: BProc, t: PNode, d: var TLoc) =
     else:
       genOrdinalCase(p, t, d)
 
+proc genRestoreFrameAfterException(p: BProc) =
+  if optStackTrace in p.module.config.options:
+    if not p.hasCurFramePointer:
+      p.hasCurFramePointer = true
+      p.procSec(cpsLocals).add(ropecg(p.module, "\tTFrame* _nimCurFrame;$n", []))
+      p.procSec(cpsInit).add(ropecg(p.module, "\t_nimCurFrame = #getFrame();$n", []))
+    linefmt(p, cpsStmts, "#setFrame(_nimCurFrame);$n")
 
 proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
   # code to generate:
@@ -794,8 +801,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
   #   finallyPart();
 
   template genExceptBranchBody(body: PNode) {.dirty.} =
-    if optStackTrace in p.options:
-      linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n")
+    genRestoreFrameAfterException(p)
     expr(p, body, d)
 
   if not isEmptyType(t.typ) and d.k == locNone:
@@ -898,8 +904,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
   endBlock(p)
   startBlock(p, "else {$n")
   linefmt(p, cpsStmts, "#popSafePoint();$n")
-  if optStackTrace in p.options:
-    linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n")
+  genRestoreFrameAfterException(p)
   p.nestedTryStmts[^1].inExcept = true
   var i = 1
   while (i < length) and (t.sons[i].kind == nkExceptBranch):
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index ce3fc2f90..843677654 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -69,6 +69,8 @@ type
     prc*: PSym                # the Nim proc that this C proc belongs to
     beforeRetNeeded*: bool    # true iff 'BeforeRet' label for proc is needed
     threadVarAccessed*: bool  # true if the proc already accessed some threadvar
+    hasCurFramePointer*: bool # true if _nimCurFrame var needed to recover after
+                              # exception is generated
     lastLineInfo*: TLineInfo  # to avoid generating excessive 'nimln' statements
     currLineInfo*: TLineInfo  # AST codegen will make this superfluous
     nestedTryStmts*: seq[tuple[n: PNode, inExcept: bool]]
diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim
index 86b63e34b..5568fd37b 100644
--- a/compiler/closureiters.nim
+++ b/compiler/closureiters.nim
@@ -155,6 +155,10 @@ type
     nearestFinally: int # Index of the nearest finally block. For try/except it
                     # is their finally. For finally it is parent finally. Otherwise -1
 
+const
+  nkSkip = { nkEmpty..nkNilLit, nkTemplateDef, nkTypeSection, nkStaticStmt,
+            nkCommentStmt } + procDefs
+
 proc newStateAccess(ctx: var Ctx): PNode =
   if ctx.stateVarSym.isNil:
     result = rawIndirectAccess(newSymNode(getEnvParam(ctx.fn)),
@@ -247,8 +251,7 @@ proc hasYields(n: PNode): bool =
   case n.kind
   of nkYieldStmt:
     result = true
-  of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit,
-      nkSym, nkIdent, procDefs, nkTemplateDef:
+  of nkSkip:
     discard
   else:
     for c in n:
@@ -259,8 +262,7 @@ proc hasYields(n: PNode): bool =
 proc transformBreaksAndContinuesInWhile(ctx: var Ctx, n: PNode, before, after: PNode): PNode =
   result = n
   case n.kind
-  of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit,
-      nkSym, nkIdent, procDefs, nkTemplateDef:
+  of nkSkip:
     discard
   of nkWhileStmt: discard # Do not recurse into nested whiles
   of nkContinueStmt:
@@ -279,8 +281,7 @@ proc transformBreaksAndContinuesInWhile(ctx: var Ctx, n: PNode, before, after: P
 proc transformBreaksInBlock(ctx: var Ctx, n: PNode, label, after: PNode): PNode =
   result = n
   case n.kind
-  of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit,
-      nkSym, nkIdent, procDefs, nkTemplateDef:
+  of nkSkip:
     discard
   of nkBlockStmt, nkWhileStmt:
     inc ctx.blockLevel
@@ -380,8 +381,7 @@ proc getFinallyNode(n: PNode): PNode =
 
 proc hasYieldsInExpressions(n: PNode): bool =
   case n.kind
-  of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit,
-      nkSym, nkIdent, procDefs, nkTemplateDef:
+  of nkSkip:
     discard
   of nkStmtListExpr:
     if isEmptyType(n.typ):
@@ -397,18 +397,17 @@ proc hasYieldsInExpressions(n: PNode): bool =
 
 proc exprToStmtList(n: PNode): tuple[s, res: PNode] =
   assert(n.kind == nkStmtListExpr)
+  result.s = newNodeI(nkStmtList, n.info)
+  result.s.sons = @[]
 
-  var parent = n
-  var lastSon = n[^1]
+  var n = n
+  while n.kind == nkStmtListExpr:
+    result.s.sons.add(n.sons)
+    result.s.sons.setLen(result.s.sons.len - 1) # delete last son
+    n = n[^1]
 
-  while lastSon.kind == nkStmtListExpr:
-    parent = lastSon
-    lastSon = lastSon[^1]
+  result.res = n
 
-  result.s = newNodeI(nkStmtList, n.info)
-  result.s.sons = parent.sons
-  result.s.sons.setLen(result.s.sons.len - 1) # delete last son
-  result.res = lastSon
 
 proc newEnvVarAsgn(ctx: Ctx, s: PSym, v: PNode): PNode =
   result = newTree(nkFastAsgn, ctx.newEnvVarAccess(s), v)
@@ -433,8 +432,7 @@ proc newNotCall(g: ModuleGraph; e: PNode): PNode =
 proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
   result = n
   case n.kind
-  of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit,
-      nkSym, nkIdent, procDefs, nkTemplateDef:
+  of nkSkip:
     discard
 
   of nkYieldStmt:
@@ -443,7 +441,6 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
       n[i] = ctx.lowerStmtListExprs(n[i], ns)
 
     if ns:
-      assert(n[0].kind == nkStmtListExpr)
       result = newNodeI(nkStmtList, n.info)
       let (st, ex) = exprToStmtList(n[0])
       result.add(st)
@@ -663,7 +660,6 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
       c[^1] = ctx.lowerStmtListExprs(c[^1], ns)
       if ns:
         needsSplit = true
-        assert(c[^1].kind == nkStmtListExpr)
         let (st, ex) = exprToStmtList(c[^1])
         result.add(st)
         c[^1] = ex
@@ -736,6 +732,33 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
 
         n[0] = newSymNode(ctx.g.getSysSym(n[0].info, "true"))
         n[1] = newBody
+
+  of nkDotExpr:
+    var ns = false
+    n[0] = ctx.lowerStmtListExprs(n[0], ns)
+    if ns:
+      needsSplit = true
+      result = newNodeI(nkStmtListExpr, n.info)
+      result.typ = n.typ
+      let (st, ex) = exprToStmtList(n[0])
+      result.add(st)
+      n[0] = ex
+      result.add(n)
+
+  of nkBlockExpr:
+    var ns = false
+    n[1] = ctx.lowerStmtListExprs(n[1], ns)
+    if ns:
+      needsSplit = true
+      result = newNodeI(nkStmtListExpr, n.info)
+      result.typ = n.typ
+      let (st, ex) = exprToStmtList(n[1])
+      n.kind = nkBlockStmt
+      n.typ = nil
+      n[1] = st
+      result.add(n)
+      result.add(ex)
+
   else:
     for i in 0 ..< n.len:
       n[i] = ctx.lowerStmtListExprs(n[i], needsSplit)
@@ -797,8 +820,7 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode =
     let goto = newTree(nkGotoState, ctx.g.newIntLit(n.info, ctx.nearestFinally))
     result.add(goto)
 
-  of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit,
-      nkSym, nkIdent, procDefs, nkTemplateDef:
+  of nkSkip:
     discard
   else:
     for i in 0 ..< n.len:
@@ -807,8 +829,7 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode =
 proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode =
   result = n
   case n.kind:
-    of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit,
-        nkSym, nkIdent, procDefs, nkTemplateDef:
+    of nkSkip:
       discard
 
     of nkStmtList, nkStmtListExpr:
@@ -846,8 +867,8 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
       result[0] = ctx.transformClosureIteratorBody(result[0], gotoOut)
 
     of nkElifBranch, nkElifExpr, nkOfBranch:
-      result[1] = addGotoOut(result[1], gotoOut)
-      result[1] = ctx.transformClosureIteratorBody(result[1], gotoOut)
+      result[^1] = addGotoOut(result[^1], gotoOut)
+      result[^1] = ctx.transformClosureIteratorBody(result[^1], gotoOut)
 
     of nkIfStmt, nkCaseStmt:
       for i in 0 ..< n.len:
@@ -1013,8 +1034,7 @@ proc tranformStateAssignments(ctx: var Ctx, n: PNode): PNode =
       for i in 0 ..< n.len:
         n[i] = ctx.tranformStateAssignments(n[i])
 
-  of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit,
-      nkSym, nkIdent, procDefs, nkTemplateDef:
+  of nkSkip:
     discard
 
   of nkReturnStmt:
@@ -1066,8 +1086,7 @@ proc skipEmptyStates(ctx: Ctx, stateIdx: int): int =
 proc skipThroughEmptyStates(ctx: var Ctx, n: PNode): PNode =
   result = n
   case n.kind
-  of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit,
-      nkSym, nkIdent, procDefs, nkTemplateDef:
+  of nkSkip:
     discard
   of nkGotoState:
     result = copyTree(n)
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index 591561987..d498cf4af 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -25,7 +25,7 @@ const
   SymChars*: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
   SymStartChars*: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
   OpChars*: set[char] = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
-    '|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'}
+    '|', '=', '%', '&', '$', '@', '~', ':'}
 
 # don't forget to update the 'highlite' module if these charsets should change
 
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index de98a5e42..d3fa506cb 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -374,6 +374,10 @@ proc processPush(c: PContext, n: PNode, start: int) =
       x.otherPragmas.add n.sons[i]
     #localError(c.config, n.info, errOptionExpected)
 
+  # If stacktrace is disabled globally we should not enable it
+  if optStackTrace notin c.optionStack[0].options:
+    c.config.options.excl(optStackTrace)
+
 proc processPop(c: PContext, n: PNode) =
   if c.optionStack.len <= 1:
     localError(c.config, n.info, "{.pop.} without a corresponding {.push.}")
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 41cac2a4a..fcfdda8bb 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -2013,6 +2013,14 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
           if r == isGeneric:
             result.typ = getInstantiatedType(c, arg, m, base(f))
           m.baseTypeMatch = true
+        # bug #4799, varargs accepting subtype relation object
+        elif r == isSubtype:
+          inc(m.subtypeMatches)
+          if f.kind == tyTypeDesc:
+            result = arg
+          else:
+            result = implicitConv(nkHiddenSubConv, f, arg, m, c)
+          m.baseTypeMatch = true
         else:
           result = userConvMatch(c, m, base(f), a, arg)
           if result != nil: m.baseTypeMatch = true
diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim
index 4f1264c9e..fbd2d7eca 100644
--- a/lib/packages/docutils/highlite.nim
+++ b/lib/packages/docutils/highlite.nim
@@ -130,7 +130,7 @@ proc nimNumber(g: var GeneralTokenizer, position: int): int =
 
 const
   OpChars  = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
-              '|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'}
+              '|', '=', '%', '&', '$', '@', '~', ':'}
 
 proc nimNextToken(g: var GeneralTokenizer) =
   const
diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim
index 96a6fa158..4665ad25f 100644
--- a/lib/pure/asyncmacro.nim
+++ b/lib/pure/asyncmacro.nim
@@ -62,52 +62,6 @@ template createCb(retFutureSym, iteratorNameSym,
 
   identName()
   #{.pop.}
-proc generateExceptionCheck(futSym,
-    tryStmt, rootReceiver, fromNode: NimNode): NimNode {.compileTime.} =
-  if tryStmt.kind == nnkNilLit:
-    result = rootReceiver
-  else:
-    var exceptionChecks: seq[tuple[cond, body: NimNode]] = @[]
-    let errorNode = newDotExpr(futSym, newIdentNode("error"))
-    for i in 1 ..< tryStmt.len:
-      let exceptBranch = tryStmt[i]
-      if exceptBranch[0].kind == nnkStmtList:
-        exceptionChecks.add((newIdentNode("true"), exceptBranch[0]))
-      else:
-        var exceptIdentCount = 0
-        var ifCond: NimNode
-        for i in 0 ..< exceptBranch.len:
-          let child = exceptBranch[i]
-          if child.kind == nnkIdent:
-            let cond = infix(errorNode, "of", child)
-            if exceptIdentCount == 0:
-              ifCond = cond
-            else:
-              ifCond = infix(ifCond, "or", cond)
-          else:
-            break
-          exceptIdentCount.inc
-
-        expectKind(exceptBranch[exceptIdentCount], nnkStmtList)
-        exceptionChecks.add((ifCond, exceptBranch[exceptIdentCount]))
-    # -> -> else: raise futSym.error
-    exceptionChecks.add((newIdentNode("true"),
-        newNimNode(nnkRaiseStmt).add(errorNode)))
-    # Read the future if there is no error.
-    # -> else: futSym.read
-    let elseNode = newNimNode(nnkElse, fromNode)
-    elseNode.add newNimNode(nnkStmtList, fromNode)
-    elseNode[0].add rootReceiver
-
-    let ifBody = newStmtList()
-    ifBody.add newCall(newIdentNode("setCurrentException"), errorNode)
-    ifBody.add newIfStmt(exceptionChecks)
-    ifBody.add newCall(newIdentNode("setCurrentException"), newNilLit())
-
-    result = newIfStmt(
-      (newDotExpr(futSym, newIdentNode("failed")), ifBody)
-    )
-    result.add elseNode
 
 template useVar(result: var NimNode, futureVarNode: NimNode, valueReceiver,
                 rootReceiver: untyped, fromNode: NimNode) =
@@ -123,8 +77,7 @@ template useVar(result: var NimNode, futureVarNode: NimNode, valueReceiver,
   result.add newNimNode(nnkYieldStmt, fromNode).add(futureVarNode)
   # -> future<x>.read
   valueReceiver = newDotExpr(futureVarNode, newIdentNode("read"))
-  result.add generateExceptionCheck(futureVarNode, tryStmt, rootReceiver,
-      fromNode)
+  result.add rootReceiver
 
 template createVar(result: var NimNode, futSymName: string,
                    asyncProc: NimNode,
@@ -154,8 +107,8 @@ proc createFutureVarCompletions(futureVarIdents: seq[NimNode],
     )
 
 proc processBody(node, retFutureSym: NimNode,
-                 subTypeIsVoid: bool, futureVarIdents: seq[NimNode],
-                 tryStmt: NimNode): NimNode {.compileTime.} =
+                 subTypeIsVoid: bool,
+                 futureVarIdents: seq[NimNode]): NimNode {.compileTime.} =
   #echo(node.treeRepr)
   result = node
   case node.kind
@@ -173,7 +126,7 @@ proc processBody(node, retFutureSym: NimNode,
         result.add newCall(newIdentNode("complete"), retFutureSym)
     else:
       let x = node[0].processBody(retFutureSym, subTypeIsVoid,
-                                  futureVarIdents, tryStmt)
+                                  futureVarIdents)
       if x.kind == nnkYieldStmt: result.add x
       else:
         result.add newCall(newIdentNode("complete"), retFutureSym, x)
@@ -224,63 +177,11 @@ proc processBody(node, retFutureSym: NimNode,
       var newDiscard = node
       result.createVar("futureDiscard_" & $toStrLit(node[0][1]), node[0][1],
                 newDiscard[0], newDiscard, node)
-  of nnkTryStmt:
-    # try: await x; except: ...
-    result = newNimNode(nnkStmtList, node)
-    template wrapInTry(n, tryBody: untyped) =
-      var temp = n
-      n[0] = tryBody
-      tryBody = temp
-
-      # Transform ``except`` body.
-      # TODO: Could we perform some ``await`` transformation here to get it
-      # working in ``except``?
-      tryBody[1] = processBody(n[1], retFutureSym, subTypeIsVoid,
-                               futureVarIdents, nil)
-
-    proc processForTry(n: NimNode, i: var int,
-                       res: NimNode): bool {.compileTime.} =
-      ## Transforms the body of the tryStmt. Does not transform the
-      ## body in ``except``.
-      ## Returns true if the tryStmt node was transformed into an ifStmt.
-      result = false
-      var skipped = n.skipStmtList()
-      while i < skipped.len:
-        var processed = processBody(skipped[i], retFutureSym,
-                                    subTypeIsVoid, futureVarIdents, n)
-
-        # Check if we transformed the node into an exception check.
-        # This suggests skipped[i] contains ``await``.
-        if processed.kind != skipped[i].kind or processed.len != skipped[i].len:
-          processed = processed.skipUntilStmtList()
-          expectKind(processed, nnkStmtList)
-          expectKind(processed[2][1], nnkElse)
-          i.inc
-
-          if not processForTry(n, i, processed[2][1][0]):
-            # We need to wrap the nnkElse nodes back into a tryStmt.
-            # As they are executed if an exception does not happen
-            # inside the awaited future.
-            # The following code will wrap the nodes inside the
-            # original tryStmt.
-            wrapInTry(n, processed[2][1][0])
-
-          res.add processed
-          result = true
-        else:
-          res.add skipped[i]
-          i.inc
-    var i = 0
-    if not processForTry(node, i, result):
-      # If the tryStmt hasn't been transformed we can just put the body
-      # back into it.
-      wrapInTry(node, result)
-    return
   else: discard
 
   for i in 0 ..< result.len:
     result[i] = processBody(result[i], retFutureSym, subTypeIsVoid,
-                            futureVarIdents, nil)
+                            futureVarIdents)
 
 proc getName(node: NimNode): string {.compileTime.} =
   case node.kind
@@ -362,7 +263,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
   # ->   complete(retFuture, result)
   var iteratorNameSym = genSym(nskIterator, $prcName & "Iter")
   var procBody = prc.body.processBody(retFutureSym, subtypeIsVoid,
-                                    futureVarIdents, nil)
+                                    futureVarIdents)
   # don't do anything with forward bodies (empty)
   if procBody.kind != nnkEmpty:
     procBody.add(createFutureVarCompletions(futureVarIdents, nil))
diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim
index 5ae5e26b2..c94e08098 100644
--- a/lib/pure/collections/critbits.nim
+++ b/lib/pure/collections/critbits.nim
@@ -165,16 +165,18 @@ proc containsOrIncl*(c: var CritBitTree[void], key: string): bool =
 
 proc inc*(c: var CritBitTree[int]; key: string, val: int = 1) =
   ## increments `c[key]` by `val`.
-  let oldCount = c.count
   var n = rawInsert(c, key)
-  if c.count == oldCount or oldCount == 0:
-    # not a new key:
-    inc n.val, val
+  inc n.val, val
 
 proc incl*(c: var CritBitTree[void], key: string) =
   ## includes `key` in `c`.
   discard rawInsert(c, key)
 
+proc incl*[T](c: var CritBitTree[T], key: string, val: T) =
+  ## inserts `key` with value `val` into `c`.
+  var n = rawInsert(c, key)
+  n.val = val
+
 proc `[]=`*[T](c: var CritBitTree[T], key: string, val: T) =
   ## puts a (key, value)-pair into `t`.
   var n = rawInsert(c, key)
@@ -322,10 +324,14 @@ proc `$`*[T](c: CritBitTree[T]): string =
       const avgItemLen = 16
     result = newStringOfCap(c.count * avgItemLen)
     result.add("{")
-    for key, val in pairs(c):
-      if result.len > 1: result.add(", ")
-      result.add($key)
-      when T isnot void:
+    when T is void:
+      for key in keys(c):
+        if result.len > 1: result.add(", ")
+        result.addQuoted(key)
+    else:
+      for key, val in pairs(c):
+        if result.len > 1: result.add(", ")
+        result.addQuoted(key)
         result.add(": ")
         result.addQuoted(val)
     result.add("}")
@@ -362,3 +368,27 @@ when isMainModule:
 
   c.inc("a", -5)
   assert c["a"] == 0
+
+  c.inc("b", 2)
+  assert c["b"] == 2
+
+  c.inc("c", 3)
+  assert c["c"] == 3
+
+  c.inc("a", 1)
+  assert c["a"] == 1
+
+  var cf = CritBitTree[float]()
+
+  cf.incl("a", 1.0)
+  assert cf["a"] == 1.0
+
+  cf.incl("b", 2.0)
+  assert cf["b"] == 2.0
+
+  cf.incl("c", 3.0)
+  assert cf["c"] == 3.0
+
+  assert cf.len == 3
+  cf.excl("c")
+  assert cf.len == 2
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index e7ad5bd5a..1bd53edb7 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -328,14 +328,14 @@ proc toJson(x: NimNode): NimNode {.compiletime.} =
     result = newNimNode(nnkBracket)
     for i in 0 ..< x.len:
       result.add(toJson(x[i]))
-    result = newCall(bindSym"%", result)
+    result = newCall(bindSym("%", brOpen), result)
   of nnkTableConstr: # object
     if x.len == 0: return newCall(bindSym"newJObject")
     result = newNimNode(nnkTableConstr)
     for i in 0 ..< x.len:
       x[i].expectKind nnkExprColonExpr
       result.add newTree(nnkExprColonExpr, x[i][0], toJson(x[i][1]))
-    result = newCall(bindSym"%", result)
+    result = newCall(bindSym("%", brOpen), result)
   of nnkCurly: # empty object
     x.expectLen(0)
     result = newCall(bindSym"newJObject")
@@ -343,9 +343,9 @@ proc toJson(x: NimNode): NimNode {.compiletime.} =
     result = newCall(bindSym"newJNull")
   of nnkPar:
     if x.len == 1: result = toJson(x[0])
-    else: result = newCall(bindSym"%", x)
+    else: result = newCall(bindSym("%", brOpen), x)
   else:
-    result = newCall(bindSym"%", x)
+    result = newCall(bindSym("%", brOpen), x)
 
 macro `%*`*(x: untyped): untyped =
   ## Convert an expression to a JsonNode directly, without having to specify
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index bf5f3f57e..5d2efebee 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -405,33 +405,40 @@ proc isIpAddress*(address_str: string): bool {.tags: [].} =
     return false
   return true
 
-proc toSockAddr*(address: IpAddress, port: Port, sa: var Sockaddr_storage, sl: var Socklen) =
+proc toSockAddr*(address: IpAddress, port: Port, sa: var Sockaddr_storage,
+                 sl: var Socklen) =
   ## Converts `IpAddress` and `Port` to `SockAddr` and `Socklen`
   let port = htons(uint16(port))
   case address.family
   of IpAddressFamily.IPv4:
     sl = sizeof(Sockaddr_in).Socklen
     let s = cast[ptr Sockaddr_in](addr sa)
-    s.sin_family = type(s.sin_family)(AF_INET)
+    s.sin_family = type(s.sin_family)(toInt(AF_INET))
     s.sin_port = port
-    copyMem(addr s.sin_addr, unsafeAddr address.address_v4[0], sizeof(s.sin_addr))
+    copyMem(addr s.sin_addr, unsafeAddr address.address_v4[0],
+            sizeof(s.sin_addr))
   of IpAddressFamily.IPv6:
     sl = sizeof(Sockaddr_in6).Socklen
     let s = cast[ptr Sockaddr_in6](addr sa)
-    s.sin6_family = type(s.sin6_family)(AF_INET6)
+    s.sin6_family = type(s.sin6_family)(toInt(AF_INET6))
     s.sin6_port = port
-    copyMem(addr s.sin6_addr, unsafeAddr address.address_v6[0], sizeof(s.sin6_addr))
+    copyMem(addr s.sin6_addr, unsafeAddr address.address_v6[0],
+            sizeof(s.sin6_addr))
 
-proc fromSockAddrAux(sa: ptr Sockaddr_storage, sl: Socklen, address: var IpAddress, port: var Port) =
-  if sa.ss_family.int == AF_INET.int and sl == sizeof(Sockaddr_in).Socklen:
+proc fromSockAddrAux(sa: ptr Sockaddr_storage, sl: Socklen,
+                     address: var IpAddress, port: var Port) =
+  if sa.ss_family.int == toInt(AF_INET) and sl == sizeof(Sockaddr_in).Socklen:
     address = IpAddress(family: IpAddressFamily.IPv4)
     let s = cast[ptr Sockaddr_in](sa)
-    copyMem(addr address.address_v4[0], addr s.sin_addr, sizeof(address.address_v4))
+    copyMem(addr address.address_v4[0], addr s.sin_addr,
+            sizeof(address.address_v4))
     port = ntohs(s.sin_port).Port
-  elif sa.ss_family.int == AF_INET6.int and sl == sizeof(Sockaddr_in6).Socklen:
+  elif sa.ss_family.int == toInt(AF_INET6) and
+       sl == sizeof(Sockaddr_in6).Socklen:
     address = IpAddress(family: IpAddressFamily.IPv6)
     let s = cast[ptr Sockaddr_in6](sa)
-    copyMem(addr address.address_v6[0], addr s.sin6_addr, sizeof(address.address_v6))
+    copyMem(addr address.address_v6[0], addr s.sin6_addr,
+            sizeof(address.address_v6))
     port = ntohs(s.sin6_port).Port
   else:
     raise newException(ValueError, "Neither IPv4 nor IPv6")
@@ -440,7 +447,7 @@ proc fromSockAddr*(sa: Sockaddr_storage | SockAddr | Sockaddr_in | Sockaddr_in6,
     sl: Socklen, address: var IpAddress, port: var Port) {.inline.} =
   ## Converts `SockAddr` and `Socklen` to `IpAddress` and `Port`. Raises
   ## `ObjectConversionError` in case of invalid `sa` and `sl` arguments.
-  fromSockAddrAux(unsafeAddr sa, sl, address, port)
+  fromSockAddrAux(cast[ptr Sockaddr_storage](unsafeAddr sa), sl, address, port)
 
 when defineSsl:
   CRYPTO_malloc_init()
@@ -1149,7 +1156,7 @@ proc waitFor(socket: Socket, waited: var float, timeout, size: int,
           return 1
         let sslPending = SSLPending(socket.sslHandle)
         if sslPending != 0:
-          return sslPending
+          return min(sslPending, size)
 
     var startTime = epochTime()
     let selRet = select(socket, timeout - int(waited * 1000.0))
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 60b362665..7cecc31ab 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -185,8 +185,7 @@ type
 
   DurationParts* = array[FixedTimeUnit, int64] # Array of Duration parts starts
   TimeIntervalParts* = array[TimeUnit, int] # Array of Duration parts starts
-
-
+  TimesMutableTypes = DateTime | Time | Duration | TimeInterval
 
 {.deprecated: [TMonth: Month, TWeekDay: WeekDay, TTime: Time,
     TTimeInterval: TimeInterval, TTimeInfo: DateTime, TimeInfo: DateTime].}
@@ -607,30 +606,12 @@ proc `+`*(a: Time, b: Duration): Time {.operator, extern: "ntAddTime".} =
     doAssert (fromUnix(0) + initDuration(seconds = 1)) == fromUnix(1)
   addImpl[Time](a, b)
 
-proc `+=`*(a: var Time, b: Duration) {.operator.} =
-  ## Modify ``a`` in place by subtracting ``b``.
-  runnableExamples:
-    var tm = fromUnix(0)
-    tm += initDuration(seconds = 1)
-    doAssert tm == fromUnix(1)
-
-  a = addImpl[Time](a, b)
-
 proc `-`*(a: Time, b: Duration): Time {.operator, extern: "ntSubTime".} =
   ## Subtracts a duration of time from a ``Time``.
   runnableExamples:
     doAssert (fromUnix(0) - initDuration(seconds = 1)) == fromUnix(-1)
   subImpl[Time](a, b)
 
-proc `-=`*(a: var Time, b: Duration) {.operator.} =
-  ## Modify ``a`` in place by adding ``b``.
-  runnableExamples:
-    var tm = fromUnix(0)
-    tm -= initDuration(seconds = 1)
-    doAssert tm == fromUnix(-1)
-
-  a = subImpl[Time](a, b)
-
 proc `<`*(a, b: Time): bool {.operator, extern: "ntLtTime".} =
   ## Returns true iff ``a < b``, that is iff a happened before b.
   ltImpl(a, b)
@@ -1377,17 +1358,6 @@ proc `+`*(time: Time, interval: TimeInterval): Time =
   else:
     toTime(time.local + interval)
 
-proc `+=`*(time: var Time, interval: TimeInterval) =
-  ## Modifies `time` by adding `interval`.
-  ## If `interval` contains any years, months, weeks or days the operation
-  ## is performed in the local timezone.
-  runnableExamples:
-    var tm = fromUnix(0)
-    tm += 5.seconds
-    doAssert tm == fromUnix(5)
-
-  time = time + interval
-
 proc `-`*(time: Time, interval: TimeInterval): Time =
   ## Subtracts `interval` from Time `time`.
   ## If `interval` contains any years, months, weeks or days the operation
@@ -1401,15 +1371,30 @@ proc `-`*(time: Time, interval: TimeInterval): Time =
   else:
     toTime(time.local - interval)
 
-proc `-=`*(time: var Time, interval: TimeInterval) =
-  ## Modifies `time` by subtracting `interval`.
-  ## If `interval` contains any years, months, weeks or days the operation
-  ## is performed in the local timezone.
+proc `+=`*[T, U: TimesMutableTypes](a: var T, b: U) =
+  ## Modify ``a`` in place by adding ``b``.
+  runnableExamples:
+    var tm = fromUnix(0)
+    tm += initDuration(seconds = 1)
+    doAssert tm == fromUnix(1)
+  a = a + b
+
+proc `-=`*[T, U: TimesMutableTypes](a: var T, b: U) =
+  ## Modify ``a`` in place by subtracting ``b``.
   runnableExamples:
     var tm = fromUnix(5)
-    tm -= 5.seconds
+    tm -= initDuration(seconds = 5)
     doAssert tm == fromUnix(0)
-  time = time - interval
+  a = a - b
+
+proc `*=`*[T: TimesMutableTypes, U](a: var T, b: U) =
+  # Mutable type is often multiplied by number
+  runnableExamples:
+    var dur = initDuration(seconds = 1)
+    dur *= 5
+    doAssert dur == initDuration(seconds = 5)
+
+  a = a * b
 
 proc formatToken(dt: DateTime, token: string, buf: var string) =
   ## Helper of the format proc to parse individual tokens.
diff --git a/lib/system.nim b/lib/system.nim
index b8aa170ea..fee9dc314 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -2681,7 +2681,7 @@ when not defined(nimscript) and hasAlloc:
       {.warning: "GC_unref is a no-op in JavaScript".}
 
     template GC_getStatistics*(): string =
-      {.warning: "GC_disableMarkAndSweep is a no-op in JavaScript".}
+      {.warning: "GC_getStatistics is a no-op in JavaScript".}
       ""
 
 template accumulateResult*(iter: untyped) =
diff --git a/lib/system/channels.nim b/lib/system/channels.nim
index 3c5bda4b1..254b87dfc 100644
--- a/lib/system/channels.nim
+++ b/lib/system/channels.nim
@@ -116,7 +116,7 @@ proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
       if mode == mStore:
         x[] = alloc0(t.region, seq.len *% mt.base.size +% GenericSeqSize)
       else:
-        unsureAsgnRef(x, newObj(mt, seq.len * mt.base.size + GenericSeqSize))
+        unsureAsgnRef(x, newSeq(mt, seq.len))
       var dst = cast[ByteAddress](cast[PPointer](dest)[])
       var dstseq = cast[PGenericSeq](dst)
       dstseq.len = seq.len
diff --git a/tests/async/t7985.nim b/tests/async/t7985.nim
new file mode 100644
index 000000000..0365499d3
--- /dev/null
+++ b/tests/async/t7985.nim
@@ -0,0 +1,19 @@
+discard """
+  file: "t7985.nim"
+  exitcode: 0
+  output: "(value: 1)"
+"""
+import json, asyncdispatch
+
+proc getData(): Future[JsonNode] {.async.} =
+  result = %*{"value": 1}
+
+type
+  MyData = object
+    value: BiggestInt
+
+proc main() {.async.} =
+  let data = to(await(getData()), MyData)
+  echo data
+
+waitFor(main())
diff --git a/tests/async/tasync_traceback.nim b/tests/async/tasync_traceback.nim
index 618a1dc76..b6c6a916b 100644
--- a/tests/async/tasync_traceback.nim
+++ b/tests/async/tasync_traceback.nim
@@ -3,7 +3,7 @@ discard """
   disabled: "windows"
   output: "Matched"
 """
-import asyncdispatch
+import asyncdispatch, strutils
 
 # Tests to ensure our exception trace backs are friendly.
 
@@ -117,10 +117,26 @@ Exception message: bar failure
 Exception type:
 """
 
-if result.match(re(expected)):
-  echo("Matched")
-else:
-  echo("Not matched!")
+let resLines = splitLines(result.strip)
+let expLines = splitLines(expected.strip)
+
+if resLines.len != expLines.len:
+  echo("Not matched! Wrong number of lines!")
   echo()
   echo(result)
   quit(QuitFailure)
+
+var ok = true
+for i in 0 ..< resLines.len:
+  if not resLines[i].match(re(expLines[i])):
+    echo "Not matched! Line ", i + 1
+    echo "Expected:"
+    echo expLines[i]
+    echo "Actual:"
+    echo resLines[i]
+    ok = false
+
+if ok:
+  echo("Matched")
+else:
+  quit(QuitFailure)
diff --git a/tests/async/tasynctry.nim b/tests/async/tasynctry.nim
index 5930f296f..6749aabbf 100644
--- a/tests/async/tasynctry.nim
+++ b/tests/async/tasynctry.nim
@@ -9,7 +9,7 @@ Multiple except branches
 Multiple except branches 2
 '''
 """
-import asyncdispatch
+import asyncdispatch, strutils
 
 # Here we are testing the ability to catch exceptions.
 
@@ -22,7 +22,7 @@ proc catch() {.async.} =
   try:
     await foobar()
   except:
-    echo("Generic except: ", getCurrentExceptionMsg())
+    echo("Generic except: ", getCurrentExceptionMsg().splitLines[0])
 
   try:
     await foobar()
diff --git a/tests/async/tasynctry2.nim b/tests/async/tasynctry2.nim
index f82b6cfe0..4b3f17cc5 100644
--- a/tests/async/tasynctry2.nim
+++ b/tests/async/tasynctry2.nim
@@ -1,7 +1,7 @@
 discard """
   file: "tasynctry2.nim"
   errormsg: "\'yield\' cannot be used within \'try\' in a non-inlined iterator"
-  line: 17
+  line: 14
 """
 import asyncdispatch
 
diff --git a/tests/collections/tcollections_to_string.nim b/tests/collections/tcollections_to_string.nim
index 48b06a6aa..0c4f1e91c 100644
--- a/tests/collections/tcollections_to_string.nim
+++ b/tests/collections/tcollections_to_string.nim
@@ -68,15 +68,15 @@ block:
 block:
   var t: CritBitTree[int]
   t["a"] = 1
-  doAssert $t == "{a: 1}"
+  doAssert $t == """{"a": 1}"""
 block:
   var t: CritBitTree[string]
   t["a"] = "1"
-  doAssert $t == """{a: "1"}"""
+  doAssert $t == """{"a": "1"}"""
 block:
   var t: CritBitTree[char]
   t["a"] = '1'
-  doAssert $t == "{a: '1'}"
+  doAssert $t == """{"a": '1'}"""
 
 
 # Test escaping behavior
diff --git a/tests/iter/tyieldintry.nim b/tests/iter/tyieldintry.nim
index 31ec65a83..6f0acb169 100644
--- a/tests/iter/tyieldintry.nim
+++ b/tests/iter/tyieldintry.nim
@@ -368,5 +368,40 @@ block: # Short cirquits
 
   test(it, 1, 0, 0)
 
+block: #7969
+  type
+    SomeObj = object
+      id: int
+
+  iterator it(): int {.closure.} =
+    template yieldAndSomeObj: SomeObj =
+      var s: SomeObj
+      s.id = 2
+      yield 1
+      s
+
+    checkpoint(yieldAndSomeObj().id)
+
+    var i = 5
+    case i
+    of 0:
+      checkpoint(123)
+    of 1, 2, 5:
+      checkpoint(3)
+    else:
+      checkpoint(123)
+
+  test(it, 1, 2, 3)
+
+block: # yield in blockexpr
+  iterator it(): int {.closure.} =
+    yield(block:
+      checkpoint(1)
+      yield 2
+      3
+    )
+
+  test(it, 1, 2, 3)
+
 
 echo "ok"
diff --git a/tests/lexer/thexlit.nim b/tests/lexer/thexlit.nim
deleted file mode 100644
index 2b7f0a40e..000000000
--- a/tests/lexer/thexlit.nim
+++ /dev/null
@@ -1,12 +0,0 @@
-discard """
-  file: "thexlit.nim"
-  output: "equal"
-"""
-
-var t=0x950412DE
-
-if t==0x950412DE:
-    echo "equal"
-else:
-    echo "not equal"
-
diff --git a/tests/lexer/thexrange.nim b/tests/lexer/thexrange.nim
deleted file mode 100644
index 461e41dfd..000000000
--- a/tests/lexer/thexrange.nim
+++ /dev/null
@@ -1,8 +0,0 @@
-
-type
-  TArray = array[0x0012..0x0013, int]
-
-var a: TArray
-
-echo a[0x0012] #OUT 0
-
diff --git a/tests/lexer/tlexermisc.nim b/tests/lexer/tlexermisc.nim
new file mode 100644
index 000000000..3e3993599
--- /dev/null
+++ b/tests/lexer/tlexermisc.nim
@@ -0,0 +1,27 @@
+discard """
+  action: run
+  output: "equal"
+"""
+
+var t=0x950412DE
+
+if t==0x950412DE:
+    echo "equal"
+else:
+    echo "not equal"
+
+type
+  TArray = array[0x0012..0x0013, int]
+
+var a: TArray
+
+doAssert a[0x0012] == 0
+
+
+# #7884
+
+type Obj = object
+    ö: int
+
+let o = Obj(ö: 1)
+doAssert o.ö == 1
diff --git a/tests/stdlib/tnet.nim b/tests/stdlib/tnet.nim
index 64d690fc9..d364447da 100644
--- a/tests/stdlib/tnet.nim
+++ b/tests/stdlib/tnet.nim
@@ -66,6 +66,18 @@ block: # "IpAddress/Sockaddr conversion"
     doAssert(ipaddr_1 == ipaddr_2)
     doAssert($ipaddr_1 == $ipaddr_2)
 
+    if sockaddr.ss_family == AF_INET.toInt:
+      var sockaddr4: Sockaddr_in
+      copyMem(addr sockaddr4, addr sockaddr, sizeof(sockaddr4))
+      fromSockAddr(sockaddr4, socklen, ipaddr_2, port_2)
+    elif sockaddr.ss_family == AF_INET6.toInt:
+      var sockaddr6: Sockaddr_in6
+      copyMem(addr sockaddr6, addr sockaddr, sizeof(sockaddr6))
+      fromSockAddr(sockaddr6, socklen, ipaddr_2, port_2)
+
+    doAssert(ipaddr_1 == ipaddr_2)
+    doAssert($ipaddr_1 == $ipaddr_2)
+
 
   # ipv6 address of example.com
   test("2606:2800:220:1:248:1893:25c8:1946")
diff --git a/tests/system/tsystem_misc.nim b/tests/system/tsystem_misc.nim
index 85228e9e7..6d14aa68f 100644
--- a/tests/system/tsystem_misc.nim
+++ b/tests/system/tsystem_misc.nim
@@ -11,6 +11,10 @@ discard """
 2
 3
 4
+2
+1
+2
+3
 '''
 """
 
@@ -47,3 +51,38 @@ foo(toOpenArray(arr, 8, 12))
 
 var seqq = @[1, 2, 3, 4, 5]
 foo(toOpenArray(seqq, 1, 3))
+
+# empty openArray issue #7904
+foo(toOpenArray(seqq, 0, -1))
+foo(toOpenArray(seqq, 1, 0))
+doAssertRaises(IndexError):
+  foo(toOpenArray(seqq, 0, -2))
+
+foo(toOpenArray(arr, 9, 8))
+foo(toOpenArray(arr, 0, -1))
+foo(toOpenArray(arr, 1, 0))
+doAssertRaises(IndexError):
+  foo(toOpenArray(arr, 10, 8))
+
+# test openArray of openArray
+proc oaEmpty(a: openArray[int]) =
+  foo(toOpenArray(a, 0, -1))
+
+proc oaFirstElm(a: openArray[int]) =
+  foo(toOpenArray(a, 0, 0))
+
+oaEmpty(toOpenArray(seqq, 0, -1))
+oaEmpty(toOpenArray(seqq, 1, 0))
+oaEmpty(toOpenArray(seqq, 1, 2))
+oaFirstElm(toOpenArray(seqq, 1, seqq.len-1))
+
+var arrNeg: array[-3 .. -1, int] = [1, 2, 3]
+foo(toOpenArray(arrNeg, -3, -1))
+foo(toOpenArray(arrNeg, 0, -1))
+foo(toOpenArray(arrNeg, -3, -4))
+doAssertRaises(IndexError):
+  foo(toOpenArray(arrNeg, -4, -1))
+doAssertRaises(IndexError):
+  foo(toOpenArray(arrNeg, -1, 0))
+doAssertRaises(IndexError):
+  foo(toOpenArray(arrNeg, -1, -3))
diff --git a/tests/typerel/t4799.nim b/tests/typerel/t4799.nim
new file mode 100644
index 000000000..075893476
--- /dev/null
+++ b/tests/typerel/t4799.nim
@@ -0,0 +1,245 @@
+discard """
+  output: "OK"
+"""
+
+type
+  GRBase[T] = ref object of RootObj
+    val: T
+  GRC[T] = ref object of GRBase[T]
+  GRD[T] = ref object of GRBase[T]
+
+proc testGR[T](x: varargs[GRBase[T]]): string =
+  result = ""
+  for c in x:
+    result.add $c.val
+
+block test_t4799_1:
+  var rgv = GRBase[int](val: 3)
+  var rgc = GRC[int](val: 4)
+  var rgb = GRD[int](val: 2)
+  doAssert(testGR(rgb, rgc, rgv) == "243")
+  doAssert(testGR(rgc, rgv, rgb) == "432")
+  doAssert(testGR(rgv, rgb, rgc) == "324")
+  doAssert(testGR([rgb, rgc, rgv]) == "243")
+  doAssert(testGR([rgc, rgv, rgb]) == "432")
+  doAssert(testGR([rgv, rgb, rgc]) == "324")
+
+type
+  PRBase[T] = object of RootObj
+    val: T
+  PRC[T] = object of PRBase[T]
+  PRD[T] = object of PRBase[T]
+
+proc testPR[T](x: varargs[ptr PRBase[T]]): string =
+  result = ""
+  for c in x:
+    result.add $c.val
+
+block test_t4799_2:
+  var pgv = PRBase[int](val: 3)
+  var pgc = PRC[int](val: 4)
+  var pgb = PRD[int](val: 2)
+  doAssert(testPR(pgb.addr, pgc.addr, pgv.addr) == "243")
+  doAssert(testPR(pgc.addr, pgv.addr, pgb.addr) == "432")
+  doAssert(testPR(pgv.addr, pgb.addr, pgc.addr) == "324")
+  doAssert(testPR([pgb.addr, pgc.addr, pgv.addr]) == "243")
+  doAssert(testPR([pgc.addr, pgv.addr, pgb.addr]) == "432")
+  doAssert(testPR([pgv.addr, pgb.addr, pgc.addr]) == "324")
+
+type
+  RBase = ref object of RootObj
+    val: int
+  RC = ref object of RBase
+  RD = ref object of RBase
+
+proc testR(x: varargs[RBase]): string =
+  result = ""
+  for c in x:
+    result.add $c.val
+
+block test_t4799_3:
+  var rv = RBase(val: 3)
+  var rc = RC(val: 4)
+  var rb = RD(val: 2)
+  doAssert(testR(rb, rc, rv) == "243")
+  doAssert(testR(rc, rv, rb) == "432")
+  doAssert(testR(rv, rb, rc) == "324")
+  doAssert(testR([rb, rc, rv]) == "243")
+  doAssert(testR([rc, rv, rb]) == "432")
+  doAssert(testR([rv, rb, rc]) == "324")
+
+type
+  PBase = object of RootObj
+    val: int
+  PC = object of PBase
+  PD = object of PBase
+
+proc testP(x: varargs[ptr PBase]): string =
+  result = ""
+  for c in x:
+    result.add $c.val
+
+block test_t4799_4:
+  var pv = PBase(val: 3)
+  var pc = PC(val: 4)
+  var pb = PD(val: 2)
+  doAssert(testP(pb.addr, pc.addr, pv.addr) == "243")
+  doAssert(testP(pc.addr, pv.addr, pb.addr) == "432")
+  doAssert(testP(pv.addr, pb.addr, pc.addr) == "324")
+  doAssert(testP([pb.addr, pc.addr, pv.addr]) == "243")
+  doAssert(testP([pc.addr, pv.addr, pb.addr]) == "432")
+  doAssert(testP([pv.addr, pb.addr, pc.addr]) == "324")
+
+type
+  PSBase[T, V] = ref object of RootObj
+    val: T
+    color: V
+  PSRC[T] = ref object of PSBase[T, int]
+  PSRD[T] = ref object of PSBase[T, int]
+
+proc testPS[T, V](x: varargs[PSBase[T, V]]): string =
+  result = ""
+  for c in x:
+    result.add c.val
+    result.add $c.color
+
+block test_t4799_5:
+  var a = PSBase[string, int](val: "base", color: 1)
+  var b = PSRC[string](val: "rc", color: 2)
+  var c = PSRD[string](val: "rd", color: 3)
+
+  doAssert(testPS(a, b, c) == "base1rc2rd3")
+  doAssert(testPS(b, a, c) == "rc2base1rd3")
+  doAssert(testPS(c, b, a) == "rd3rc2base1")
+  doAssert(testPS([a, b, c]) == "base1rc2rd3")
+  doAssert(testPS([b, a, c]) == "rc2base1rd3")
+  doAssert(testPS([c, b, a]) == "rd3rc2base1")
+
+type
+  SBase[T, V] = ref object of RootObj
+    val: T
+    color: V
+  SRC = ref object of SBase[string, int]
+  SRD = ref object of SBase[string, int]
+
+proc testS[T, V](x: varargs[SBase[T, V]]): string =
+  result = ""
+  for c in x:
+    result.add c.val
+    result.add $c.color
+
+block test_t4799_6:
+  var a = SBase[string, int](val: "base", color: 1)
+  var b = SRC(val: "rc", color: 2)
+  var c = SRD(val: "rd", color: 3)
+
+  doAssert(testS(a, b, c) == "base1rc2rd3")
+  doAssert(testS(b, a, c) == "rc2base1rd3")
+  doAssert(testS(c, b, a) == "rd3rc2base1")
+  doAssert(testS([a, b, c]) == "base1rc2rd3")
+  # this is not varargs bug, but array construction bug
+  # see #7955
+  #doAssert(testS([b, c, a]) == "rc2rd3base1")
+  #doAssert(testS([c, b, a]) == "rd3rc2base1")
+
+proc test_inproc() =
+  block test_inproc_1:
+    var rgv = GRBase[int](val: 3)
+    var rgc = GRC[int](val: 4)
+    var rgb = GRD[int](val: 2)
+    doAssert(testGR(rgb, rgc, rgv) == "243")
+    doAssert(testGR(rgc, rgv, rgb) == "432")
+    doAssert(testGR(rgv, rgb, rgc) == "324")
+    doAssert(testGR([rgb, rgc, rgv]) == "243")
+    doAssert(testGR([rgc, rgv, rgb]) == "432")
+    doAssert(testGR([rgv, rgb, rgc]) == "324")
+
+  block test_inproc_2:
+    var pgv = PRBase[int](val: 3)
+    var pgc = PRC[int](val: 4)
+    var pgb = PRD[int](val: 2)
+    doAssert(testPR(pgb.addr, pgc.addr, pgv.addr) == "243")
+    doAssert(testPR(pgc.addr, pgv.addr, pgb.addr) == "432")
+    doAssert(testPR(pgv.addr, pgb.addr, pgc.addr) == "324")
+    doAssert(testPR([pgb.addr, pgc.addr, pgv.addr]) == "243")
+    doAssert(testPR([pgc.addr, pgv.addr, pgb.addr]) == "432")
+    doAssert(testPR([pgv.addr, pgb.addr, pgc.addr]) == "324")
+
+test_inproc()
+
+template reject(x) =
+  static: assert(not compiles(x))
+
+block test_t4799_7:
+  type
+    Vehicle[T] = ref object of RootObj
+      tire: T
+    Car[T] = object of Vehicle[T]
+    Bike[T] = object of Vehicle[T]
+
+  proc testVehicle[T](x: varargs[Vehicle[T]]): string {.used.} =
+    result = ""
+    for c in x:
+      result.add $c.tire
+
+  var v = Vehicle[int](tire: 3)
+  var c = Car[int](tire: 4)
+  var b = Bike[int](tire: 2)
+
+  reject:
+    echo testVehicle(b, c, v)
+
+block test_t4799_8:
+  type
+    Vehicle = ref object of RootObj
+      tire: int
+    Car = object of Vehicle
+    Bike = object of Vehicle
+
+  proc testVehicle(x: varargs[Vehicle]): string {.used.} =
+    result = ""
+    for c in x:
+      result.add $c.tire
+
+  var v = Vehicle(tire: 3)
+  var c = Car(tire: 4)
+  var b = Bike(tire: 2)
+
+  reject:
+    echo testVehicle(b, c, v)
+
+type
+  PGVehicle[T] = ptr object of RootObj
+    tire: T
+  PGCar[T] = object of PGVehicle[T]
+  PGBike[T] = object of PGVehicle[T]
+
+proc testVehicle[T](x: varargs[PGVehicle[T]]): string {.used.} =
+  result = ""
+  for c in x:
+    result.add $c.tire
+
+var pgc = PGCar[int](tire: 4)
+var pgb = PGBike[int](tire: 2)
+
+reject:
+  echo testVehicle(pgb, pgc)
+
+type
+  RVehicle = ptr object of RootObj
+    tire: int
+  RCar = object of RVehicle
+  RBike = object of RVehicle
+
+proc testVehicle(x: varargs[RVehicle]): string {.used.} =
+  result = ""
+  for c in x:
+    result.add $c.tire
+
+var rc = RCar(tire: 4)
+var rb = RBike(tire: 2)
+
+reject:
+  echo testVehicle(rb, rc)
+
+echo "OK"
diff --git a/tests/typerel/t4799_1.nim b/tests/typerel/t4799_1.nim
new file mode 100644
index 000000000..549b6bf3c
--- /dev/null
+++ b/tests/typerel/t4799_1.nim
@@ -0,0 +1,20 @@
+discard """
+  outputsub: '''ObjectAssignmentError'''
+  exitcode: "1"
+"""
+
+type
+  Vehicle[T] = object of RootObj
+    tire: T
+  Car[T] = object of Vehicle[T]
+  Bike[T] = object of Vehicle[T]
+
+proc testVehicle[T](x: varargs[Vehicle[T]]): string =
+  result = ""
+  for c in x:
+    result.add $c.tire
+
+var v = Vehicle[int](tire: 3)
+var c = Car[int](tire: 4)
+var b = Bike[int](tire: 2)
+echo testVehicle b, c, v
diff --git a/tests/typerel/t4799_2.nim b/tests/typerel/t4799_2.nim
new file mode 100644
index 000000000..cfd399a6e
--- /dev/null
+++ b/tests/typerel/t4799_2.nim
@@ -0,0 +1,20 @@
+discard """
+  outputsub: '''ObjectAssignmentError'''
+  exitcode: "1"
+"""
+
+type
+  Vehicle[T] = object of RootObj
+    tire: T
+  Car[T] = object of Vehicle[T]
+  Bike[T] = object of Vehicle[T]
+
+proc testVehicle[T](x: varargs[Vehicle[T]]): string =
+  result = ""
+  for c in x:
+    result.add $c.tire
+
+var v = Vehicle[int](tire: 3)
+var c = Car[int](tire: 4)
+var b = Bike[int](tire: 2)
+echo testVehicle([b, c, v])
\ No newline at end of file
diff --git a/tests/typerel/t4799_3.nim b/tests/typerel/t4799_3.nim
new file mode 100644
index 000000000..784eee8fc
--- /dev/null
+++ b/tests/typerel/t4799_3.nim
@@ -0,0 +1,20 @@
+discard """
+  outputsub: '''ObjectAssignmentError'''
+  exitcode: "1"
+"""
+
+type
+  Vehicle = object of RootObj
+    tire: int
+  Car = object of Vehicle
+  Bike = object of Vehicle
+
+proc testVehicle(x: varargs[Vehicle]): string =
+  result = ""
+  for c in x:
+    result.add $c.tire
+
+var v = Vehicle(tire: 3)
+var c = Car(tire: 4)
+var b = Bike(tire: 2)
+echo testVehicle([b, c, v])
\ No newline at end of file