summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/closureiters.nim25
-rw-r--r--compiler/jsgen.nim55
-rw-r--r--compiler/lexer.nim47
-rw-r--r--compiler/llstream.nim6
-rw-r--r--compiler/parser.nim35
-rw-r--r--compiler/pragmas.nim2
-rw-r--r--compiler/renderer.nim73
-rw-r--r--compiler/semexprs.nim3
-rw-r--r--compiler/semfold.nim75
-rw-r--r--compiler/transf.nim6
-rw-r--r--lib/js/asyncjs.nim16
-rw-r--r--lib/nimbase.h2
-rw-r--r--lib/pure/asyncdispatch.nim6
-rw-r--r--lib/pure/asyncmacro.nim2
-rw-r--r--lib/pure/memfiles.nim1
-rw-r--r--lib/pure/strscans.nim6
-rw-r--r--lib/pure/strutils.nim2
-rw-r--r--lib/system.nim9
-rw-r--r--lib/system/jssys.nim20
-rw-r--r--tests/arithm/tcast.nim43
-rw-r--r--tests/ccgbugs/t5345.nim10
-rw-r--r--tests/ccgbugs/t5701.nim17
-rw-r--r--tests/ccgbugs/tcodegendecllambda.nim13
-rw-r--r--tests/iter/tyieldintry.nim36
-rw-r--r--tests/js/t7224.nim26
-rw-r--r--tests/js/t7249.nim21
-rw-r--r--tests/js/t7534.nim7
-rw-r--r--tests/js/t8914.nim12
-rw-r--r--tests/js/tmangle.nim8
-rw-r--r--tests/js/tstringitems.nim2
-rw-r--r--tests/macros/tmacrostmt.nim47
-rw-r--r--tests/typerel/t8905.nim7
32 files changed, 489 insertions, 151 deletions
diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim
index 71c755d6c..b0857e6c7 100644
--- a/compiler/closureiters.nim
+++ b/compiler/closureiters.nim
@@ -678,7 +678,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
       n[0] = ex
       result.add(n)
 
-  of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv:
+  of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv, nkObjDownConv:
     var ns = false
     for i in 0 ..< n.len:
       n[i] = ctx.lowerStmtListExprs(n[i], ns)
@@ -687,9 +687,9 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
       needsSplit = true
       result = newNodeI(nkStmtListExpr, n.info)
       result.typ = n.typ
-      let (st, ex) = exprToStmtList(n[1])
+      let (st, ex) = exprToStmtList(n[^1])
       result.add(st)
-      n[1] = ex
+      n[^1] = ex
       result.add(n)
 
   of nkAsgn, nkFastAsgn:
@@ -712,6 +712,25 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
 
       result.add(n)
 
+  of nkBracketExpr:
+    var lhsNeedsSplit = false
+    var rhsNeedsSplit = false
+    n[0] = ctx.lowerStmtListExprs(n[0], lhsNeedsSplit)
+    n[1] = ctx.lowerStmtListExprs(n[1], rhsNeedsSplit)
+    if lhsNeedsSplit or rhsNeedsSplit:
+      needsSplit = true
+      result = newNodeI(nkStmtListExpr, n.info)
+      if lhsNeedsSplit:
+        let (st, ex) = exprToStmtList(n[0])
+        result.add(st)
+        n[0] = ex
+
+      if rhsNeedsSplit:
+        let (st, ex) = exprToStmtList(n[1])
+        result.add(st)
+        n[1] = ex
+      result.add(n)
+
   of nkWhileStmt:
     var ns = false
 
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 1b00ddbfa..16ed9dc17 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -658,15 +658,16 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
   line(p, "}\L")
 
 proc genRaiseStmt(p: PProc, n: PNode) =
-  genLineDir(p, n)
   if n.sons[0].kind != nkEmpty:
     var a: TCompRes
     gen(p, n.sons[0], a)
     let typ = skipTypes(n.sons[0].typ, abstractPtrs)
+    genLineDir(p, n)
     useMagic(p, "raiseException")
     lineF(p, "raiseException($1, $2);$n",
              [a.rdLoc, makeJSString(typ.sym.name.s)])
   else:
+    genLineDir(p, n)
     useMagic(p, "reraiseException")
     line(p, "reraiseException();\L")
 
@@ -764,11 +765,22 @@ proc genAsmOrEmitStmt(p: PProc, n: PNode) =
     of nkSym:
       let v = it.sym
       # for backwards compatibility we don't deref syms here :-(
-      if v.kind in {skVar, skLet, skTemp, skConst, skResult, skParam, skForVar}:
-        p.body.add mangleName(p.module, v)
+      if false:
+        discard
       else:
         var r: TCompRes
         gen(p, it, r)
+
+        if it.typ.kind == tyPointer:
+          # A fat pointer is disguised as an array
+          r.res = r.address
+          r.address = nil
+        elif r.typ == etyBaseIndex:
+          # Deference first
+          r.res = "$1[$2]" % [r.address, r.res]
+          r.address = nil
+          r.typ = etyNone
+
         p.body.add(r.rdLoc)
     else:
       var r: TCompRes
@@ -845,6 +857,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
   else:
     gen(p, x, a)
 
+  genLineDir(p, y)
   gen(p, y, b)
 
   # we don't care if it's an etyBaseIndex (global) of a string, it's
@@ -881,11 +894,9 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
     lineF(p, "$1 = $2;$n", [a.res, b.res])
 
 proc genAsgn(p: PProc, n: PNode) =
-  genLineDir(p, n)
   genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=false)
 
 proc genFastAsgn(p: PProc, n: PNode) =
-  genLineDir(p, n)
   # 'shallowCopy' always produced 'noCopyNeeded = true' here but this is wrong
   # for code like
   #  while j >= pos:
@@ -1529,18 +1540,18 @@ proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
   if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyChar:
     r.res.add("[$1].concat(" % [a.res])
   else:
-    r.res.add("($1.slice(0,-1)).concat(" % [a.res])
+    r.res.add("($1).concat(" % [a.res])
 
   for i in countup(2, sonsLen(n) - 2):
     gen(p, n.sons[i], a)
     if skipTypes(n.sons[i].typ, abstractVarRange).kind == tyChar:
       r.res.add("[$1]," % [a.res])
     else:
-      r.res.add("$1.slice(0,-1)," % [a.res])
+      r.res.add("$1," % [a.res])
 
   gen(p, n.sons[sonsLen(n) - 1], a)
   if skipTypes(n.sons[sonsLen(n) - 1].typ, abstractVarRange).kind == tyChar:
-    r.res.add("[$1, 0])" % [a.res])
+    r.res.add("[$1])" % [a.res])
   else:
     r.res.add("$1)" % [a.res])
 
@@ -1647,13 +1658,13 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
     else: unaryExpr(p, n, r, "subInt", "subInt($1, 1)")
   of mAppendStrCh:
     binaryExpr(p, n, r, "addChar",
-        "if ($1 != null) { addChar($1, $2); } else { $1 = [$2, 0]; }")
+        "if ($1 != null) { addChar($1, $2); } else { $1 = [$2]; }")
   of mAppendStrStr:
     if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:
         binaryExpr(p, n, r, "", "if ($1 != null) { $1 += $2; } else { $1 = $2; }")
     else:
       binaryExpr(p, n, r, "",
-        "if ($1 != null) { $1 = ($1.slice(0, -1)).concat($2); } else { $1 = $2;}")
+        "if ($1 != null) { $1 = ($1).concat($2); } else { $1 = $2;}")
     # XXX: make a copy of $2, because of Javascript's sucking semantics
   of mAppendSeqElem:
     var x, y: TCompRes
@@ -1683,20 +1694,15 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
   of mChr, mArrToSeq: gen(p, n.sons[1], r)      # nothing to do
   of mOrd: genOrd(p, n, r)
   of mLengthStr:
-    if n.sons[1].typ.skipTypes(abstractInst).kind == tyCString:
-      unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)")
-    else:
-      unaryExpr(p, n, r, "", "($1 != null ? $1.length-1 : 0)")
-  of mXLenStr: unaryExpr(p, n, r, "", "$1.length-1")
+    unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)")
+  of mXLenStr:
+    unaryExpr(p, n, r, "", "$1.length")
   of mLengthSeq, mLengthOpenArray, mLengthArray:
     unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)")
   of mXLenSeq:
     unaryExpr(p, n, r, "", "$1.length")
   of mHigh:
-    if skipTypes(n.sons[1].typ, abstractVar).kind == tyString:
-      unaryExpr(p, n, r, "", "($1 != null ? ($1.length-2) : -1)")
-    else:
-      unaryExpr(p, n, r, "", "($1 != null ? ($1.length-1) : -1)")
+    unaryExpr(p, n, r, "", "($1 != null ? ($1.length-1) : -1)")
   of mInc:
     if n[1].typ.skipTypes(abstractRange).kind in tyUInt .. tyUInt64:
       binaryUintExpr(p, n, r, "+", true)
@@ -1710,7 +1716,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
       if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
       else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)")
   of mSetLengthStr:
-    binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0")
+    binaryExpr(p, n, r, "", "$1.length = $2")
   of mSetLengthSeq:
     var x, y: TCompRes
     gen(p, n.sons[1], x)
@@ -1739,8 +1745,6 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
     localError(p.config, n.info, errXMustBeCompileTime % n.sons[0].sym.name.s)
   of mCopyStr:
     binaryExpr(p, n, r, "", "($1.slice($2))")
-  of mCopyStrLast:
-    ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))")
   of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)")
   of mNewStringOfCap:
     unaryExpr(p, n, r, "mnewString", "mnewString(0)")
@@ -2065,8 +2069,11 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
       r.kind = resExpr
   of nkStrLit..nkTripleStrLit:
     if skipTypes(n.typ, abstractVarRange).kind == tyString:
-      useMagic(p, "makeNimstrLit")
-      r.res = "makeNimstrLit($1)" % [makeJSString(n.strVal)]
+      if n.strVal.len != 0:
+        useMagic(p, "makeNimstrLit")
+        r.res = "makeNimstrLit($1)" % [makeJSString(n.strVal)]
+      else:
+        r.res = rope"[]"
     else:
       r.res = makeJSString(n.strVal, false)
     r.kind = resExpr
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index 6ad1d9fc6..278fa1e54 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -884,6 +884,42 @@ proc getOperator(L: var TLexer, tok: var TToken) =
   if buf[pos] in {CR, LF, nimlexbase.EndOfFile}:
     tok.strongSpaceB = -1
 
+proc getPrecedence*(tok: TToken, strongSpaces: bool): int =
+  ## Calculates the precedence of the given token.
+  template considerStrongSpaces(x): untyped =
+    x + (if strongSpaces: 100 - tok.strongSpaceA.int*10 else: 0)
+
+  case tok.tokType
+  of tkOpr:
+    let L = tok.ident.s.len
+    let relevantChar = tok.ident.s[0]
+
+    # arrow like?
+    if L > 1 and tok.ident.s[L-1] == '>' and
+      tok.ident.s[L-2] in {'-', '~', '='}: return considerStrongSpaces(1)
+
+    template considerAsgn(value: untyped) =
+      result = if tok.ident.s[L-1] == '=': 1 else: value
+
+    case relevantChar
+    of '$', '^': considerAsgn(10)
+    of '*', '%', '/', '\\': considerAsgn(9)
+    of '~': result = 8
+    of '+', '-', '|': considerAsgn(8)
+    of '&': considerAsgn(7)
+    of '=', '<', '>', '!': result = 5
+    of '.': considerAsgn(6)
+    of '?': result = 2
+    else: considerAsgn(2)
+  of tkDiv, tkMod, tkShl, tkShr: result = 9
+  of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5
+  of tkDotDot: result = 6
+  of tkAnd: result = 4
+  of tkOr, tkXor, tkPtr, tkRef: result = 3
+  else: return -10
+  result = considerStrongSpaces(result)
+
+
 proc newlineFollows*(L: TLexer): bool =
   var pos = L.bufpos
   var buf = L.buf
@@ -1249,3 +1285,14 @@ proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream;
     result = tok.indent
     if result > 0 or tok.tokType == tkEof: break
   closeLexer(lex)
+
+proc getPrecedence*(ident: PIdent): int =
+  ## assumes ident is binary operator already
+  var tok: TToken
+  initToken(tok)
+  tok.ident = ident
+  tok.tokType =
+    if tok.ident.id in ord(tokKeywordLow) - ord(tkSymbol) .. ord(tokKeywordHigh) - ord(tkSymbol):
+      TTokType(tok.ident.id + ord(tkSymbol))
+    else: tkOpr
+  getPrecedence(tok, false)
diff --git a/compiler/llstream.nim b/compiler/llstream.nim
index 42bbb7600..9cd329320 100644
--- a/compiler/llstream.nim
+++ b/compiler/llstream.nim
@@ -87,9 +87,9 @@ proc endsWithOpr*(x: string): bool =
   result = x.endsWith(LineContinuationOprs)
 
 proc continueLine(line: string, inTripleString: bool): bool {.inline.} =
-  result = inTripleString or
-      line[0] == ' ' or
-      line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs)
+  result = inTripleString or line.len > 0 and (
+        line[0] == ' ' or
+        line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs))
 
 proc countTriples(s: string): int =
   var i = 0
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 246dcb814..f15449c85 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -252,41 +252,6 @@ proc isRightAssociative(tok: TToken): bool {.inline.} =
   result = tok.tokType == tkOpr and tok.ident.s[0] == '^'
   # or (let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>'))
 
-proc getPrecedence(tok: TToken, strongSpaces: bool): int =
-  ## Calculates the precedence of the given token.
-  template considerStrongSpaces(x): untyped =
-    x + (if strongSpaces: 100 - tok.strongSpaceA.int*10 else: 0)
-
-  case tok.tokType
-  of tkOpr:
-    let L = tok.ident.s.len
-    let relevantChar = tok.ident.s[0]
-
-    # arrow like?
-    if L > 1 and tok.ident.s[L-1] == '>' and
-      tok.ident.s[L-2] in {'-', '~', '='}: return considerStrongSpaces(1)
-
-    template considerAsgn(value: untyped) =
-      result = if tok.ident.s[L-1] == '=': 1 else: value
-
-    case relevantChar
-    of '$', '^': considerAsgn(10)
-    of '*', '%', '/', '\\': considerAsgn(9)
-    of '~': result = 8
-    of '+', '-', '|': considerAsgn(8)
-    of '&': considerAsgn(7)
-    of '=', '<', '>', '!': result = 5
-    of '.': considerAsgn(6)
-    of '?': result = 2
-    else: considerAsgn(2)
-  of tkDiv, tkMod, tkShl, tkShr: result = 9
-  of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5
-  of tkDotDot: result = 6
-  of tkAnd: result = 4
-  of tkOr, tkXor, tkPtr, tkRef: result = 3
-  else: return -10
-  result = considerStrongSpaces(result)
-
 proc isOperator(tok: TToken): bool =
   ## Determines if the given token is an operator type token.
   tok.tokType in {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs,
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 7aa674800..9a344c038 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -53,7 +53,7 @@ const
   lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
     wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
     wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
-    wRaises, wLocks, wTags, wGcSafe}
+    wRaises, wLocks, wTags, wGcSafe, wCodegenDecl}
   typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
     wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wExtern, wShallow,
     wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index a8f3f4afc..aa666290c 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -307,14 +307,19 @@ proc lsub(g: TSrcGen; n: PNode): int
 proc litAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string =
   proc skip(t: PType): PType =
     result = t
-    while result.kind in {tyGenericInst, tyRange, tyVar, tyLent, tyDistinct,
+    while result != nil and result.kind in {tyGenericInst, tyRange, tyVar, tyLent, tyDistinct,
                           tyOrdinal, tyAlias, tySink}:
       result = lastSon(result)
-  if n.typ != nil and n.typ.skip.kind in {tyBool, tyEnum}:
-    let enumfields = n.typ.skip.n
+  let typ = n.typ.skip
+  if typ != nil and typ.kind in {tyBool, tyEnum}:
+    if sfPure in typ.sym.flags:
+      result = typ.sym.name.s & '.'
+    let enumfields = typ.n
     # we need a slow linear search because of enums with holes:
     for e in items(enumfields):
-      if e.sym.position == x: return e.sym.name.s
+      if e.sym.position == x: 
+        result &= e.sym.name.s
+        return
 
   if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
   elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3)
@@ -861,6 +866,47 @@ proc isBracket*(n: PNode): bool =
   of nkSym: result = n.sym.name.s == "[]"
   else: result = false
 
+proc skipHiddenNodes(n: PNode): PNode = 
+  result = n
+  while result != nil:
+    if result.kind in {nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv} and result.len > 1: 
+      result = result[1]
+    elif result.kind in {nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref, nkStringToCString, nkCStringToString} and
+        result.len > 0: 
+      result = result[0]
+    else: break
+
+proc accentedName(g: var TSrcGen, n: PNode) =
+  if n == nil: return
+  let isOperator = 
+    if n.kind == nkIdent and n.ident.s.len > 0 and n.ident.s[0] in OpChars: true
+    elif n.kind == nkSym and n.sym.name.s.len > 0 and n.sym.name.s[0] in OpChars: true
+    else: false
+
+  if isOperator:
+    put(g, tkAccent, "`")
+    gident(g, n)
+    put(g, tkAccent, "`")
+  else:
+    gsub(g, n)
+
+proc infixArgument(g: var TSrcGen, n: PNode, i: int) =
+  if i >= n.len: return
+
+  var needsParenthesis = false
+  let n_next = n[i].skipHiddenNodes
+  if n_next.kind == nkInfix:
+    if n_next[0].kind in {nkSym, nkIdent} and n[0].kind in {nkSym, nkIdent}:
+      let nextId = if n_next[0].kind == nkSym: n_next[0].sym.name else: n_next[0].ident
+      let nnId = if n[0].kind == nkSym: n[0].sym.name else: n[0].ident     
+      if getPrecedence(nextId) < getPrecedence(nnId):
+        needsParenthesis = true
+  if needsParenthesis:
+    put(g, tkParLe, "(")
+  gsub(g, n, i)
+  if needsParenthesis:
+    put(g, tkParRi, ")")
+  
 proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
   if isNil(n): return
   var
@@ -896,7 +942,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       gcomma(g, n, 2)
       put(g, tkBracketRi, "]")
     elif n.len > 1 and n.lastSon.kind == nkStmtList:
-      gsub(g, n[0])
+      accentedName(g, n[0])
       if n.len > 2:
         put(g, tkParLe, "(")
         gcomma(g, n, 1, -2)
@@ -904,16 +950,16 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       put(g, tkColon, ":")
       gsub(g, n, n.len-1)
     else:
-      if sonsLen(n) >= 1: gsub(g, n.sons[0])
+      if sonsLen(n) >= 1: accentedName(g, n[0])
       put(g, tkParLe, "(")
       gcomma(g, n, 1)
       put(g, tkParRi, ")")
   of nkCallStrLit:
-    gsub(g, n, 0)
+    if n.len > 0: accentedName(g, n[0])
     if n.len > 1 and n.sons[1].kind == nkRStrLit:
       put(g, tkRStrLit, '\"' & replace(n[1].strVal, "\"", "\"\"") & '\"')
     else:
-      gsub(g, n.sons[1])
+      gsub(g, n, 1)
   of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv:
     if n.len >= 2:
       gsub(g, n.sons[1])
@@ -951,7 +997,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     gsub(g, n, 0)
     gcomma(g, n, 1)
   of nkCommand:
-    gsub(g, n, 0)
+    accentedName(g, n[0])
     put(g, tkSpaces, Space)
     gcomma(g, n, 1)
   of nkExprEqExpr, nkAsgn, nkFastAsgn:
@@ -1064,14 +1110,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     putWithSpace(g, tkColon, ":")
     gsub(g, n, 1)
   of nkInfix:
-    gsub(g, n, 1)
+    infixArgument(g, n, 1)
     put(g, tkSpaces, Space)
     gsub(g, n, 0)        # binary operator
     if not fits(g, lsub(g, n.sons[2]) + lsub(g, n.sons[0]) + 1):
       optNL(g, g.indent + longIndentWid)
     else:
       put(g, tkSpaces, Space)
-    gsub(g, n, 2)
+    infixArgument(g, n, 2)
   of nkPrefix:
     gsub(g, n, 0)
     if n.len > 1:
@@ -1079,10 +1125,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
                 elif n[0].kind == nkSym: n[0].sym.name
                 elif n[0].kind in {nkOpenSymChoice, nkClosedSymChoice}: n[0][0].sym.name
                 else: nil
-      var n_next = n[1]
-      while n_next.kind in {nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref,
-                  nkStringToCString, nkCStringToString} and n_next.len > 0:
-        n_next = n_next[0]
+      let n_next = skipHiddenNodes(n[1])
       if n_next.kind == nkPrefix or (opr != nil and renderer.isKeyword(opr)):
         put(g, tkSpaces, Space)
       if n_next.kind == nkInfix:
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index ce953f17c..e527b06cc 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -113,6 +113,7 @@ proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
     if castDest.kind notin IntegralTypes+{tyRange}:
       result = convNotNeedeed
     return
+  # Save for later
   var d = skipTypes(castDest, abstractVar)
   var s = src
   if s.kind in tyUserTypeClasses and s.isResolvedUserTypeClass:
@@ -135,7 +136,7 @@ proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
     # we use d, s here to speed up that operation a bit:
     case cmpTypes(c, d, s)
     of isNone, isGeneric:
-      if not compareTypes(castDest, src, dcEqIgnoreDistinct):
+      if not compareTypes(castDest.skipTypes(abstractVar), src, dcEqIgnoreDistinct):
         result = convNotLegal
     else:
       discard
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 27a6af1f4..0018f0755 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -214,7 +214,24 @@ proc evalIs(n: PNode, lhs: PSym, g: ModuleGraph): PNode =
   result = newIntNode(nkIntLit, ord(res))
   result.typ = n.typ
 
+proc fitLiteral(c: ConfigRef, n: PNode): PNode =
+  # Trim the literal value in order to make it fit in the destination type
+  if n == nil:
+    # `n` may be nil if the overflow check kicks in
+    return
+
+  doAssert n.kind in {nkIntLit, nkCharLit}
+
+  result = n
+
+  let typ = n.typ.skipTypes(abstractRange)
+  if typ.kind in tyUInt..tyUint32:
+    result.intVal = result.intVal and lastOrd(c, typ, fixedUnsigned=true)
+
 proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
+  template doAndFit(op: untyped): untyped =
+    # Implements wrap-around behaviour for unsigned types
+    fitLiteral(g.config, op)
   # b and c may be nil
   result = nil
   case m
@@ -224,12 +241,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
   of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n, g)
   of mNot: result = newIntNodeT(1 - getInt(a), n, g)
   of mCard: result = newIntNodeT(nimsets.cardSet(g.config, a), n, g)
-  of mBitnotI:
-    case skipTypes(n.typ, abstractRange).kind
-    of tyUInt..tyUInt64:
-      result = newIntNodeT((not getInt(a)) and lastOrd(g.config, a.typ, fixedUnsigned=true), n, g)
-    else:
-      result = newIntNodeT(not getInt(a), n, g)
+  of mBitnotI: result = doAndFit(newIntNodeT(not getInt(a), n, g))
   of mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, g)
   of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr:
     if a.kind == nkNilLit:
@@ -251,9 +263,9 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
   of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n, g)
   of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n, g)
   of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n, g)
-  of mUnaryLt: result = foldSub(getOrdValue(a), 1, n, g)
-  of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n, g)
-  of mPred: result = foldSub(getOrdValue(a), getInt(b), n, g)
+  of mUnaryLt: result = doAndFit(foldSub(getOrdValue(a), 1, n, g))
+  of mSucc: result = doAndFit(foldAdd(getOrdValue(a), getInt(b), n, g))
+  of mPred: result = doAndFit(foldSub(getOrdValue(a), getInt(b), n, g))
   of mAddI: result = foldAdd(getInt(a), getInt(b), n, g)
   of mSubI: result = foldSub(getInt(a), getInt(b), n, g)
   of mMulI: result = foldMul(getInt(a), getInt(b), n, g)
@@ -271,7 +283,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
     of tyInt64, tyInt:
       result = newIntNodeT(`shl`(getInt(a), getInt(b)), n, g)
     of tyUInt..tyUInt64:
-      result = newIntNodeT(`shl`(getInt(a), getInt(b)) and lastOrd(g.config, a.typ, fixedUnsigned=true), n, g)
+      result = doAndFit(newIntNodeT(`shl`(getInt(a), getInt(b)), n, g))
     else: internalError(g.config, n.info, "constant folding for shl")
   of mShrI:
     case skipTypes(n.typ, abstractRange).kind
@@ -324,14 +336,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
     result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n, g)
   of mLeU, mLeU64:
     result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n, g)
-  of mBitandI, mAnd: result = newIntNodeT(a.getInt and b.getInt, n, g)
-  of mBitorI, mOr: result = newIntNodeT(getInt(a) or getInt(b), n, g)
-  of mBitxorI, mXor: result = newIntNodeT(a.getInt xor b.getInt, n, g)
-  of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n, g)
-  of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n, g)
-  of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n, g)
-  of mModU: result = foldModU(getInt(a), getInt(b), n, g)
-  of mDivU: result = foldDivU(getInt(a), getInt(b), n, g)
+  of mBitandI, mAnd: result = doAndFit(newIntNodeT(a.getInt and b.getInt, n, g))
+  of mBitorI, mOr: result = doAndFit(newIntNodeT(getInt(a) or getInt(b), n, g))
+  of mBitxorI, mXor: result = doAndFit(newIntNodeT(a.getInt xor b.getInt, n, g))
+  of mAddU: result = doAndFit(newIntNodeT(`+%`(getInt(a), getInt(b)), n, g))
+  of mSubU: result = doAndFit(newIntNodeT(`-%`(getInt(a), getInt(b)), n, g))
+  of mMulU: result = doAndFit(newIntNodeT(`*%`(getInt(a), getInt(b)), n, g))
+  of mModU: result = doAndFit(foldModU(getInt(a), getInt(b), n, g))
+  of mDivU: result = doAndFit(foldDivU(getInt(a), getInt(b), n, g))
   of mLeSet: result = newIntNodeT(ord(containsSets(g.config, a, b)), n, g)
   of mEqSet: result = newIntNodeT(ord(equalSets(g.config, a, b)), n, g)
   of mLtSet:
@@ -462,17 +474,24 @@ proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode =
       result = newIntNodeT(int(getFloat(a)), n, g)
     of tyChar:
       result = newIntNodeT(getOrdValue(a), n, g)
-    of tyUInt8..tyUInt32, tyInt8..tyInt32:
-      let fromSigned = srcTyp.kind in tyInt..tyInt64
+    of tyUInt..tyUInt64, tyInt..tyInt64:
       let toSigned = dstTyp.kind in tyInt..tyInt64
-
-      let mask = lastOrd(g.config, dstTyp, fixedUnsigned=true)
-
-      var val =
-        if toSigned:
-          a.getOrdValue mod mask
-        else:
-          a.getOrdValue and mask
+      var val = a.getOrdValue
+
+      if dstTyp.kind in {tyInt, tyInt64, tyUint, tyUInt64}:
+        # No narrowing needed
+        discard
+      elif dstTyp.kind in {tyInt..tyInt64}:
+        # Signed type: Overflow check (if requested) and conversion
+        if check: rangeCheck(n, val, g)
+        let mask = (`shl`(1, getSize(g.config, dstTyp) * 8) - 1)
+        let valSign = val < 0
+        val = abs(val) and mask
+        if valSign: val = -val
+      else:
+        # Unsigned type: Conversion
+        let mask = (`shl`(1, getSize(g.config, dstTyp) * 8) - 1)
+        val = val and mask
 
       result = newIntNodeT(val, n, g)
     else:
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 84297aa6a..347df3e49 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -624,7 +624,11 @@ proc transformCase(c: PTransf, n: PNode): PTransNode =
     case it.kind
     of nkElifBranch:
       if ifs.PNode == nil:
-        ifs = newTransNode(nkIfStmt, it.info, 0)
+        # Generate the right node depending on whether `n` is used as a stmt or
+        # as an expr
+        let kind = if n.typ != nil: nkIfExpr else: nkIfStmt
+        ifs = newTransNode(kind, it.info, 0)
+        ifs.PNode.typ = n.typ
       ifs.add(e)
     of nkElse:
       if ifs.PNode == nil: result.add(e)
diff --git a/lib/js/asyncjs.nim b/lib/js/asyncjs.nim
index 894102ca0..7439b66e1 100644
--- a/lib/js/asyncjs.nim
+++ b/lib/js/asyncjs.nim
@@ -92,7 +92,10 @@ proc isFutureVoid(node: NimNode): bool =
            node[1].kind == nnkIdent and $node[1] == "void"
 
 proc generateJsasync(arg: NimNode): NimNode =
-  assert arg.kind == nnkProcDef
+  if arg.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}:
+      error("Cannot transform this node kind into an async proc." &
+            " proc/method definition or lambda node expected.")
+
   result = arg
   var isVoid = false
   let jsResolve = ident("jsResolve")
@@ -108,7 +111,7 @@ proc generateJsasync(arg: NimNode): NimNode =
 
   if len(code) > 0:
     var awaitFunction = quote:
-      proc await[T](f: Future[T]): T {.importcpp: "(await #)".}
+      proc await[T](f: Future[T]): T {.importcpp: "(await #)", used.}
     result.body.add(awaitFunction)
 
     var resolve: NimNode
@@ -117,7 +120,7 @@ proc generateJsasync(arg: NimNode): NimNode =
         var `jsResolve` {.importcpp: "undefined".}: Future[void]
     else:
       resolve = quote:
-        proc jsResolve[T](a: T): Future[T] {.importcpp: "#".}
+        proc jsResolve[T](a: T): Future[T] {.importcpp: "#", used.}
     result.body.add(resolve)
   else:
     result.body = newEmptyNode()
@@ -137,7 +140,12 @@ proc generateJsasync(arg: NimNode): NimNode =
 macro async*(arg: untyped): untyped =
   ## Macro which converts normal procedures into
   ## javascript-compatible async procedures
-  generateJsasync(arg)
+  if arg.kind == nnkStmtList:
+    result = newStmtList()
+    for oneProc in arg:
+      result.add generateJsasync(oneProc)
+  else:
+    result = generateJsasync(arg)
 
 proc newPromise*[T](handler: proc(resolve: proc(response: T))): Future[T] {.importcpp: "(new Promise(#))".}
   ## A helper for wrapping callback-based functions
diff --git a/lib/nimbase.h b/lib/nimbase.h
index 84972fcb0..507108712 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -107,6 +107,8 @@ __clang__
 #  define N_INLINE(rettype, name) rettype __inline name
 #endif
 
+#define N_INLINE_PTR(rettype, name) rettype (*name)
+
 #if defined(__POCC__)
 #  define NIM_CONST /* PCC is really picky with const modifiers */
 #  undef _MSC_VER /* Yeah, right PCC defines _MSC_VER even if it is
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 093bf58af..820f34703 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -1536,7 +1536,11 @@ proc withTimeout*[T](fut: Future[T], timeout: int): Future[bool] =
   var timeoutFuture = sleepAsync(timeout)
   fut.callback =
     proc () =
-      if not retFuture.finished: retFuture.complete(true)
+      if not retFuture.finished:
+        if fut.failed:
+          retFuture.fail(fut.error)
+        else:
+          retFuture.complete(true)
   timeoutFuture.callback =
     proc () =
       if not retFuture.finished: retFuture.complete(false)
diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim
index 4665ad25f..9e0893a4d 100644
--- a/lib/pure/asyncmacro.nim
+++ b/lib/pure/asyncmacro.nim
@@ -327,8 +327,8 @@ macro async*(prc: untyped): untyped =
   ## Macro which processes async procedures into the appropriate
   ## iterators and yield statements.
   if prc.kind == nnkStmtList:
+    result = newStmtList()
     for oneProc in prc:
-      result = newStmtList()
       result.add asyncSingleProc(oneProc)
   else:
     result = asyncSingleProc(prc)
diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim
index 0249b7413..9fccd08d4 100644
--- a/lib/pure/memfiles.nim
+++ b/lib/pure/memfiles.nim
@@ -328,7 +328,6 @@ proc `$`*(ms: MemSlice): string {.inline.} =
   ## Return a Nim string built from a MemSlice.
   var buf = newString(ms.size)
   copyMem(addr(buf[0]), ms.data, ms.size)
-  buf[ms.size] = '\0'
   result = buf
 
 iterator memSlices*(mfile: MemFile, delim='\l', eat='\r'): MemSlice {.inline.} =
diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim
index 11f182495..b17eee6ff 100644
--- a/lib/pure/strscans.nim
+++ b/lib/pure/strscans.nim
@@ -10,7 +10,7 @@
 ##[
 This module contains a `scanf`:idx: macro that can be used for extracting
 substrings from an input string. This is often easier than regular expressions.
-Some examples as an apetizer:
+Some examples as an appetizer:
 
 .. code-block:: nim
   # check if input string matches a triple of integers:
@@ -308,7 +308,7 @@ proc buildUserCall(x: string; args: varargs[NimNode]): NimNode =
     for i in 1..<y.len: result.add y[i]
 
 macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): bool =
-  ## See top level documentation of his module of how ``scanf`` works.
+  ## See top level documentation of this module about how ``scanf`` works.
   template matchBind(parser) {.dirty.} =
     var resLen = genSym(nskLet, "resLen")
     conds.add newLetStmt(resLen, newCall(bindSym(parser), inp, results[i], idx))
@@ -469,7 +469,7 @@ template success*(x: int): bool = x != 0
 template nxt*(input: string; idx, step: int = 1) = inc(idx, step)
 
 macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool =
-  ## See top level documentation of his module of how ``scanf`` works.
+  ## See top level documentation of this module about how ``scanp`` works.
   type StmtTriple = tuple[init, cond, action: NimNode]
 
   template interf(x): untyped = bindSym(x, brForceOpen)
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 7730aa7a2..396f14972 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -820,7 +820,7 @@ proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect,
     # handle negative overflow
     if n == 0 and x < 0: n = -1
 
-proc toHex*[T](x: T): string =
+proc toHex*[T: SomeInteger](x: T): string =
   ## Shortcut for ``toHex(x, T.sizeOf * 2)``
   toHex(BiggestInt(x), T.sizeOf * 2)
 
diff --git a/lib/system.nim b/lib/system.nim
index 3a18a715c..a406c7811 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1552,7 +1552,7 @@ proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
     defaultImpl()
   else:
     when defined(js):
-      {.emit: "`x`[`x`_Idx].splice(`i`, 1);".}
+      {.emit: "`x`.splice(`i`, 1);".}
     else:
       defaultImpl()
 
@@ -1574,7 +1574,7 @@ proc insert*[T](x: var seq[T], item: T, i = 0.Natural) {.noSideEffect.} =
   else:
     when defined(js):
       var it : T
-      {.emit: "`x`[`x`_Idx].splice(`i`, 0, `it`);".}
+      {.emit: "`x`.splice(`i`, 0, `it`);".}
     else:
       defaultImpl()
   x[i] = item
@@ -2741,12 +2741,11 @@ type
 when defined(JS):
   proc add*(x: var string, y: cstring) {.asmNoStackFrame.} =
     asm """
-      var len = `x`[0].length-1;
+      var len = `x`.length;
       for (var i = 0; i < `y`.length; ++i) {
-        `x`[0][len] = `y`.charCodeAt(i);
+        `x`[len] = `y`.charCodeAt(i);
         ++len;
       }
-      `x`[0][len] = 0
     """
   proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".}
 
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
index 152b48c24..836ac198d 100644
--- a/lib/system/jssys.nim
+++ b/lib/system/jssys.nim
@@ -182,12 +182,10 @@ proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} =
 proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} =
   {.emit: """
   var ln = `c`.length;
-  var result = new Array(ln + 1);
-  var i = 0;
-  for (; i < ln; ++i) {
+  var result = new Array(ln);
+  for (var i = 0; i < ln; ++i) {
     result[i] = `c`.charCodeAt(i);
   }
-  result[i] = 0; // terminating zero
   return result;
   """.}
 
@@ -225,13 +223,12 @@ proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} =
     }
     ++r;
   }
-  result[r] = 0; // terminating zero
   return result;
   """.}
 
 proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
   asm """
-  var len = `s`.length-1;
+  var len = `s`.length;
   var asciiPart = new Array(len);
   var fcc = String.fromCharCode;
   var nonAsciiPart = null;
@@ -262,10 +259,7 @@ proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
 
 proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} =
   asm """
-    var result = new Array(`len`+1);
-    result[0] = 0;
-    result[`len`] = 0;
-    return result;
+    return new Array(`len`);
   """
 
 proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} =
@@ -323,7 +317,7 @@ proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerProc.} =
     if (`a` == `b`) return 0;
     if (!`a`) return -1;
     if (!`b`) return 1;
-    for (var i = 0; i < `a`.length - 1 && i < `b`.length - 1; i++) {
+    for (var i = 0; i < `a`.length && i < `b`.length; i++) {
       var result = `a`[i] - `b`[i];
       if (result != 0) return result;
     }
@@ -651,9 +645,7 @@ proc isObj(obj, subclass: PNimType): bool {.compilerproc.} =
   return true
 
 proc addChar(x: string, c: char) {.compilerproc, asmNoStackFrame.} =
-  asm """
-    `x`[`x`.length-1] = `c`; `x`.push(0);
-  """
+  asm "`x`.push(`c`);"
 
 {.pop.}
 
diff --git a/tests/arithm/tcast.nim b/tests/arithm/tcast.nim
index 954e2e677..4017ed1c5 100644
--- a/tests/arithm/tcast.nim
+++ b/tests/arithm/tcast.nim
@@ -4,6 +4,9 @@ B0
 B1
 B2
 B3
+B4
+B5
+B6
 '''
 """
 
@@ -14,6 +17,14 @@ template crossCheck(ty: untyped, exp: untyped) =
     echo "Got ", ct
     echo "Expected ", rt
 
+template add1(x: uint8): untyped = x + 1
+template add1(x: uint16): untyped = x + 1
+template add1(x: uint32): untyped = x + 1
+
+template sub1(x: uint8): untyped = x - 1
+template sub1(x: uint16): untyped = x - 1
+template sub1(x: uint32): untyped = x - 1
+
 block:
   when true:
     echo "B0"
@@ -34,10 +45,34 @@ block:
     crossCheck(uint64, (-1).uint64 + 5'u64)
 
     echo "B3"
-    crossCheck(int8, 0'u8 - 5'u8)
-    crossCheck(int16, 0'u16 - 5'u16)
-    crossCheck(int32, 0'u32 - 5'u32)
-    crossCheck(int64, 0'u64 - 5'u64)
+    doAssert $sub1(0'u8) == "255"
+    doAssert $sub1(0'u16) == "65535"
+    doAssert $sub1(0'u32) == "4294967295"
+
+    echo "B4"
+    doAssert $add1(255'u8) == "0"
+    doAssert $add1(65535'u16) == "0"
+    doAssert $add1(4294967295'u32) == "0"
+
+    echo "B5"
+    crossCheck(int32, high(int32))
+    crossCheck(int32, high(int32).int32)
+    crossCheck(int32, low(int32))
+    crossCheck(int32, low(int32).int32)
+    crossCheck(int64, high(int8).int16.int32.int64)
+    crossCheck(int64, low(int8).int16.int32.int64)
+
+    echo "B6"
+    crossCheck(int64, 0xFFFFFFFFFFFFFFFF'u64)
+    crossCheck(int32, 0xFFFFFFFFFFFFFFFF'u64)
+    crossCheck(int16, 0xFFFFFFFFFFFFFFFF'u64)
+    crossCheck(int8 , 0xFFFFFFFFFFFFFFFF'u64)
+
+    # Out of range conversion, caught for `let`s only
+    # crossCheck(int8, 0'u8 - 5'u8)
+    # crossCheck(int16, 0'u16 - 5'u16)
+    # crossCheck(int32, 0'u32 - 5'u32)
+    # crossCheck(int64, 0'u64 - 5'u64)
 
   # crossCheck(int8, 0'u16 - 129'u16)
   # crossCheck(uint8, 0'i16 + 257'i16)
diff --git a/tests/ccgbugs/t5345.nim b/tests/ccgbugs/t5345.nim
new file mode 100644
index 000000000..f9ee833c4
--- /dev/null
+++ b/tests/ccgbugs/t5345.nim
@@ -0,0 +1,10 @@
+discard """
+  output: true
+"""
+
+proc cmpx(d: int): bool {.inline.} = d > 0
+
+proc abc[C](cx: C, d: int) =
+  echo cx(d)
+  
+abc(cmpx, 10)
diff --git a/tests/ccgbugs/t5701.nim b/tests/ccgbugs/t5701.nim
new file mode 100644
index 000000000..e69acbf31
--- /dev/null
+++ b/tests/ccgbugs/t5701.nim
@@ -0,0 +1,17 @@
+discard """
+  output: '''(Field0: 1, Field1: 1)
+(Field0: 2, Field1: 2)
+(Field0: 3, Field1: 3)
+'''
+"""
+
+iterator zip[T1, T2](a: openarray[T1], b: openarray[T2]): iterator() {.inline.} =
+  let len = min(a.len, b.len)
+  for i in 0..<len:
+    echo (a[i], b[i])
+
+proc foo(args: varargs[int]) =
+  for i in zip(args,args):
+    discard
+
+foo(1,2,3)
diff --git a/tests/ccgbugs/tcodegendecllambda.nim b/tests/ccgbugs/tcodegendecllambda.nim
new file mode 100644
index 000000000..6dce68db5
--- /dev/null
+++ b/tests/ccgbugs/tcodegendecllambda.nim
@@ -0,0 +1,13 @@
+discard """
+  targets: "c cpp js"
+  ccodecheck: "'HELLO'"
+"""
+
+when defined(JS):
+  var foo = proc(): void{.codegenDecl: "/*HELLO*/function $2($3)".} =
+    echo "baa"
+else:
+  var foo = proc(): void{.codegenDecl: "/*HELLO*/$1 $2 $3".} =
+    echo "baa"
+
+foo()
diff --git a/tests/iter/tyieldintry.nim b/tests/iter/tyieldintry.nim
index 6f0acb169..6d24417a6 100644
--- a/tests/iter/tyieldintry.nim
+++ b/tests/iter/tyieldintry.nim
@@ -403,5 +403,41 @@ block: # yield in blockexpr
 
   test(it, 1, 2, 3)
 
+block: #8851 
+  type
+    Foo = ref object of RootObj
+  template someFoo(): Foo =
+    var f: Foo
+    yield 1
+    f
+  iterator it(): int {.closure.} =
+    var o: RootRef
+    o = someFoo()
+
+  test(it, 1)
+
+block: # 8243
+  iterator it(): int {.closure.} =
+    template yieldAndSeq: seq[int] =
+      yield 1
+      @[123, 5, 123]
+
+    checkpoint(yieldAndSeq[1])
+
+  test(it, 1, 5)
+
+block:
+  iterator it(): int {.closure.} =
+    template yieldAndSeq: seq[int] =
+      yield 1
+      @[123, 5, 123]
+
+    template yieldAndNum: int =
+      yield 2
+      1
+
+    checkpoint(yieldAndSeq[yieldAndNum])
+
+  test(it, 1, 2, 5)
 
 echo "ok"
diff --git a/tests/js/t7224.nim b/tests/js/t7224.nim
new file mode 100644
index 000000000..2d7ee1336
--- /dev/null
+++ b/tests/js/t7224.nim
@@ -0,0 +1,26 @@
+discard """
+  cmd: "nim $target $options --stackTrace:on --lineTrace:on $file"
+  outputsub: '''
+t7224.aaa, line: 21
+t7224.bbb, line: 18
+t7224.ccc, line: 15
+t7224.ddd, line: 12
+'''
+"""
+  
+proc ddd() =
+  raise newException(IOError, "didn't do stuff")
+
+proc ccc() =
+  ddd()
+
+proc bbb() =
+  ccc()
+
+proc aaa() =
+  bbb()
+
+try:
+  aaa()
+except IOError as e:
+  echo getStackTrace(e)
diff --git a/tests/js/t7249.nim b/tests/js/t7249.nim
new file mode 100644
index 000000000..52eee2f7c
--- /dev/null
+++ b/tests/js/t7249.nim
@@ -0,0 +1,21 @@
+discard """
+  output: '''
+a -> 2
+a <- 2
+'''
+"""
+
+import jsffi
+
+var a = JsAssoc[cstring, int]{a: 2}
+
+for z, b in a:
+  echo z, " -> ", b
+
+proc f =
+  var a = JsAssoc[cstring, int]{a: 2}
+
+  for z, b in a:
+    echo z, " <- ", b
+
+f()
diff --git a/tests/js/t7534.nim b/tests/js/t7534.nim
new file mode 100644
index 000000000..64aadb8d6
--- /dev/null
+++ b/tests/js/t7534.nim
@@ -0,0 +1,7 @@
+proc f(x: int): int =
+  result = case x
+    of 1: 2
+    elif x == 2: 3
+    else: 1
+
+doAssert 2 == f(f(f(f(1))))
diff --git a/tests/js/t8914.nim b/tests/js/t8914.nim
new file mode 100644
index 000000000..ff716b42a
--- /dev/null
+++ b/tests/js/t8914.nim
@@ -0,0 +1,12 @@
+discard """
+  output: '''
+@[42]
+@[24, 42]
+'''
+"""
+
+var x = @[42,4242]
+x.delete(1)
+echo x
+x.insert(24)
+echo x
diff --git a/tests/js/tmangle.nim b/tests/js/tmangle.nim
index c4167ba39..c97bf7029 100644
--- a/tests/js/tmangle.nim
+++ b/tests/js/tmangle.nim
@@ -27,10 +27,10 @@ block:
   var global = T(a: 11, b: "foo")
   proc test(): bool =
     var obj = T(a: 11, b: "foo")
-    {. emit: [result, " = (", obj.addr[], "[0].a == 11);"] .}
-    {. emit: [result, " = ", result, " && (", obj.addr[], "[0].b == \"foo\");"] .}
-    {. emit: [result, " = ", result, " && (", global, "[0].a == 11);"] .}
-    {. emit: [result, " = ", result, " && (", global, "[0].b == \"foo\");"] .}
+    {. emit: [result, " = (", obj.addr[], ".a == 11);"] .}
+    {. emit: [result, " = ", result, " && (", obj.addr[], ".b == \"foo\");"] .}
+    {. emit: [result, " = ", result, " && (", global, ".a == 11);"] .}
+    {. emit: [result, " = ", result, " && (", global, ".b == \"foo\");"] .}
   echo test()
 
 # Test addr of field:
diff --git a/tests/js/tstringitems.nim b/tests/js/tstringitems.nim
index ff016642e..f09793dde 100644
--- a/tests/js/tstringitems.nim
+++ b/tests/js/tstringitems.nim
@@ -45,7 +45,7 @@ block: # Test compile-time binary data generation, invalid unicode
 block: # Test unicode strings
   const constStr = "Привет!"
   var jsStr : cstring
-  {.emit: """`jsStr`[0] = "Привет!";""".}
+  {.emit: """`jsStr` = "Привет!";""".}
 
   doAssert($jsStr == constStr)
   var runtimeStr = "При"
diff --git a/tests/macros/tmacrostmt.nim b/tests/macros/tmacrostmt.nim
index 9dbfbce43..c1f26e626 100644
--- a/tests/macros/tmacrostmt.nim
+++ b/tests/macros/tmacrostmt.nim
@@ -43,6 +43,10 @@ macro repr_and_parse(fn: typed): typed =
   echo fn_impl.repr
   result = parseStmt(fn_impl.repr)
 
+macro repr_to_string(fn: typed): string =
+  let fn_impl = fn.getImpl
+  result = newStrLitNode(fn_impl.repr)
+
 repr_and_parse(f)
 
 
@@ -70,8 +74,49 @@ proc test_cond_stmtlist(x, y: int): int =
     result = x
 
 
+#------------------------------------
+# bug #8762
+proc t2(a, b: int): int =  
+  `+`(a, b)
+
+
+#------------------------------------
+# bug #8761
+
+proc fn1(x, y: int):int =
+  2 * (x + y)
+
+proc fn2(x, y: float): float =
+  (y + 2 * x) / (x - y)
+
+proc fn3(x, y: int): bool =
+  (((x and 3) div 4) or (x mod (y xor -1))) == 0 or y notin [1,2]
+  
+static:
+  let fn1s = "proc fn1(x, y: int): int =\n  result = 2 * (x + y)\n"
+  let fn2s = "proc fn2(x, y: float): float =\n  result = (y + 2.0 * x) / (x - y)\n"
+  let fn3s = "proc fn3(x, y: int): bool =\n  result = ((x and 3) div 4 or x mod (y xor -1)) == 0 or not contains([1, 2], y)\n"
+  doAssert fn1.repr_to_string == fn1s
+  doAssert fn2.repr_to_string == fn2s
+  doAssert fn3.repr_to_string == fn3s
+
+#------------------------------------
+# bug #8763
+
+type
+  A {.pure.} = enum
+    X, Y
+  B {.pure.} = enum
+    X, Y
+
+proc test_pure_enums(a: B) =
+  case a
+    of B.X: echo B.X
+    of B.Y: echo B.Y
+
 repr_and_parse(one_if_proc)
 repr_and_parse(test_block)
 repr_and_parse(test_cond_stmtlist)
-
+repr_and_parse(t2)
+repr_and_parse(test_pure_enums)
 
diff --git a/tests/typerel/t8905.nim b/tests/typerel/t8905.nim
new file mode 100644
index 000000000..9383962cf
--- /dev/null
+++ b/tests/typerel/t8905.nim
@@ -0,0 +1,7 @@
+type
+  Foo[T] = distinct seq[T]
+  Bar[T] = object
+
+proc newFoo[T](): Foo[T] = Foo[T](newSeq[T]())
+
+var x = newFoo[Bar[int]]()