summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--changelog.md3
-rw-r--r--compiler/ccgstmts.nim50
-rw-r--r--compiler/nimsets.nim5
-rw-r--r--compiler/semcall.nim21
-rw-r--r--compiler/semstmts.nim9
-rw-r--r--compiler/semtypes.nim15
-rw-r--r--compiler/sigmatch.nim59
-rw-r--r--doc/manual/generics.txt26
-rw-r--r--lib/pure/collections/tables.nim41
-rw-r--r--lib/pure/httpclient.nim11
-rw-r--r--lib/pure/net.nim10
-rw-r--r--lib/pure/osproc.nim4
-rw-r--r--lib/pure/parsecsv.nim22
-rw-r--r--lib/pure/terminal.nim4
-rw-r--r--lib/system.nim2
-rw-r--r--tests/casestmt/tduplicates.nim50
-rw-r--r--tests/cpp/tcppraise.nim22
-rw-r--r--tests/generics/tspecial_numeric_inference.nim21
-rw-r--r--tests/iter/titer2.nim11
-rw-r--r--tests/testament/tester.nim5
20 files changed, 224 insertions, 167 deletions
diff --git a/changelog.md b/changelog.md
index 73d7e7d9b..cc57a9188 100644
--- a/changelog.md
+++ b/changelog.md
@@ -241,9 +241,6 @@ styledEcho "Red on Green.", resetStyle
   and it no longer raises an OS error but returns an ``osInvalidSocket`` when
   creation fails.
 - ``newNativeSocket`` is now named ``createNativeSocket``.
-- Type inference for generic type parameters involving numeric types is now symetric. See
-  [Generic type inference for numeric types](https://nim-lang.org/docs/manual.html#generics-generic-type-inference-fornumeric-types)
-  for more information.
 - The ``deprecated`` pragma now supports a user-definable warning message for procs.
 
 ```nim
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 9c7bced33..a69495a4b 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -788,30 +788,13 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
   #      myDiv(4, 9);
   #   } catch (NimExceptionType1&) {
   #      body
-  #      goto LA_END;
   #   } catch (NimExceptionType2&) {
   #      finallyPart()
   #      raise;
-  #      goto LA_END;
-  #   } catch (NimExceptionType3&) {goto LA1;}
-  #   } catch (NimExceptionType4&) {goto LA1;}
-  #   } catch (NimExceptionType5&) {goto LA2;}
-  #   } catch (NimExceptionType6&) {goto LA2;}
-  #   catch(...) {
-  #     // general handler
-  #     goto LA_END;
-  #   }
-  #   {LA1:
-  #      labeled_branch_body_LA1
-  #      goto LA_END;
   #   }
-  #   {LA2:
-  #      labeled_branch_body_LA2
-  #      finallyPart()
-  #      raise;
-  #      goto LA_END;
+  #   catch(...) {
+  #     general_handler_body
   #   }
-  #   LA_END:  
   #   finallyPart();
  
   template genExceptBranchBody(body: PNode) {.dirty.} =
@@ -819,22 +802,19 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
       linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n") 
     expr(p, body, d)
     linefmt(p, cpsStmts, "#popCurrentException();$n")
-    linefmt(p, cpsStmts, "goto $1;$n", end_label)
     
-
   if not isEmptyType(t.typ) and d.k == locNone:
     getTemp(p, t.typ, d)
   genLineDir(p, t)
 
+  let end_label = getLabel(p)
   discard cgsym(p.module, "Exception")
   add(p.nestedTryStmts, t)
   startBlock(p, "try {$n")
   expr(p, t[0], d)
-  endBlock(p, ropecg(p.module, "}"))
+  endBlock(p)
 
-  let end_label = getLabel(p)
   var catchAllPresent = false
-  var labeled_branches: seq[tuple[label: Rope, body: PNode]] = @[] # generated after labels discovered
 
   inc p.inExceptBlock
   for i in 1..<t.len:
@@ -849,20 +829,12 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
       startBlock(p, "catch (...) {$n")
       genExceptBranchBody(t[i][0])
       endBlock(p)
-
-    elif t[i].len == 2:
-      startBlock(p, "catch ($1*) {$n", getTypeDesc(p.module, t[i][0].typ))
-      genExceptBranchBody(t[i][^1])
-      endBlock(p)
-
     else:
-      # cpp can't catch multiple types in one statement so we need a label and goto
-      let label = getLabel(p)    
-      labeled_branches.add((label, t[i][^1]))
       for j in 0..t[i].len-2:
         assert(t[i][j].kind == nkType)
-        linefmt(p, cpsStmts, "catch ($1*) {goto $2;}$n",
-                           [getTypeDesc(p.module, t[i][j].typ), label])
+        startBlock(p, "catch ($1*) {$n", getTypeDesc(p.module, t[i][j].typ))
+        genExceptBranchBody(t[i][^1])  # exception handler body will duplicated for every type
+        endBlock(p)
 
   if not catchAllPresent and t[^1].kind == nkFinally:
     # finally requires catch all presence
@@ -871,14 +843,6 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
     line(p, cpsStmts, ~"throw;$n")
     endBlock(p)
 
-  # generate labeled branches bodies
-  for label, body in labeled_branches.items():
-    startBlock(p)
-    fixLabel(p, label)
-    genExceptBranchBody(body)
-    endBlock(p)
-  fixLabel(p, end_label)
-
   dec p.inExceptBlock
   discard pop(p.nestedTryStmts)
 
diff --git a/compiler/nimsets.nim b/compiler/nimsets.nim
index 94507adf0..bda753e85 100644
--- a/compiler/nimsets.nim
+++ b/compiler/nimsets.nim
@@ -151,6 +151,11 @@ proc complement*(a: PNode): PNode =
   for i in countup(0, high(x)): x[i] = not x[i]
   result = toTreeSet(x, a.typ, a.info)
 
+proc deduplicate*(a: PNode): PNode =
+  var x: TBitSet
+  toBitSet(a, x)
+  result = toTreeSet(x, a.typ, a.info)
+
 proc cardSet(s: PNode): BiggestInt =
   # here we can do better than converting it into a compact set
   # we just count the elements directly
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 5bdd817d5..6fef11c48 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -169,21 +169,24 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
     else:
       add(candidates, err.sym.getProcHeader(prefer))
     add(candidates, "\n")
-    if err.firstMismatch != 0 and n.len > 2:
-      add(candidates, "  first type mismatch at position: " & $err.firstMismatch &
-        "\n  required type: ")
+    if err.firstMismatch != 0 and n.len > 1:
+      let cond = n.len > 2
+      if cond:
+        candidates.add("  first type mismatch at position: " & $err.firstMismatch &
+          "\n  required type: ")
       var wanted, got: PType = nil
       if err.firstMismatch < err.sym.typ.len:
         wanted = err.sym.typ.sons[err.firstMismatch]
-        candidates.add typeToString(wanted)
+        if cond: candidates.add typeToString(wanted)
       else:
-        candidates.add "none"
+        if cond: candidates.add "none"
       if err.firstMismatch < n.len:
-        candidates.add "\n  but expression '"
-        candidates.add renderTree(n[err.firstMismatch])
-        candidates.add "' is of type: "
+        if cond:
+          candidates.add "\n  but expression '"
+          candidates.add renderTree(n[err.firstMismatch])
+          candidates.add "' is of type: "
         got = n[err.firstMismatch].typ
-        candidates.add typeToString(got)
+        if cond: candidates.add typeToString(got)
       if wanted != nil and got != nil:
         effectProblem(wanted, got, candidates)
       candidates.add "\n"
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 18b9a347b..1e3265eae 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -692,6 +692,12 @@ proc implicitIterator(c: PContext, it: string, arg: PNode): PNode =
     result.add arg
   result = semExprNoDeref(c, result, {efWantIterator})
 
+proc isTrivalStmtExpr(n: PNode): bool =
+  for i in 0 .. n.len-2:
+    if n[i].kind notin {nkEmpty, nkCommentStmt}:
+      return false
+  result = true
+
 proc semFor(c: PContext, n: PNode): PNode =
   result = n
   checkMinSonsLen(n, 3)
@@ -699,6 +705,9 @@ proc semFor(c: PContext, n: PNode): PNode =
   openScope(c)
   n.sons[length-2] = semExprNoDeref(c, n.sons[length-2], {efWantIterator})
   var call = n.sons[length-2]
+  if call.kind == nkStmtListExpr and isTrivalStmtExpr(call):
+    call = call.lastSon
+    n.sons[length-2] = call
   let isCallExpr = call.kind in nkCallKinds
   if isCallExpr and call[0].kind == nkSym and
       call[0].sym.magic in {mFields, mFieldPairs, mOmpParFor}:
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index df274c7db..50c2e287e 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -497,8 +497,8 @@ proc semCaseBranchSetElem(c: PContext, t, b: PNode,
 
 proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
                    covered: var BiggestInt) =
-
-  for i in countup(0, sonsLen(branch) - 2):
+  let lastIndex = sonsLen(branch) - 2
+  for i in 0..lastIndex:
     var b = branch.sons[i]
     if b.kind == nkRange:
       branch.sons[i] = b
@@ -516,14 +516,21 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
         branch.sons[i] = skipConv(fitNode(c, t.sons[0].typ, r, r.info))
         inc(covered)
       else:
+        if r.kind == nkCurly:
+          r = r.deduplicate
+
         # first element is special and will overwrite: branch.sons[i]:
         branch.sons[i] = semCaseBranchSetElem(c, t, r[0], covered)
+
         # other elements have to be added to ``branch``
         for j in 1 ..< r.len:
           branch.add(semCaseBranchSetElem(c, t, r[j], covered))
           # caution! last son of branch must be the actions to execute:
-          var L = branch.len
-          swap(branch.sons[L-2], branch.sons[L-1])
+          swap(branch.sons[^2], branch.sons[^1])
+    checkForOverlap(c, t, i, branchIndex)
+
+  # Elements added above needs to be checked for overlaps.
+  for i in lastIndex.succ..(sonsLen(branch) - 2):
     checkForOverlap(c, t, i, branchIndex)
 
 proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index aba36d24d..9f802a10e 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -915,24 +915,25 @@ proc isCovariantPtr(c: var TCandidate, f, a: PType): bool =
   else:
     return false
 
-proc maxNumericType(prev, candidate: PType): PType =
-  let c = candidate.skipTypes({tyRange})
-  template greater(s) =
-    if c.kind in s: result = c
-  case prev.kind
-  of tyInt: greater({tyInt64})
-  of tyInt8: greater({tyInt, tyInt16, tyInt32, tyInt64})
-  of tyInt16: greater({tyInt, tyInt32, tyInt64})
-  of tyInt32: greater({tyInt64})
-
-  of tyUInt: greater({tyUInt64})
-  of tyUInt8: greater({tyUInt, tyUInt16, tyUInt32, tyUInt64})
-  of tyUInt16: greater({tyUInt, tyUInt32, tyUInt64})
-  of tyUInt32: greater({tyUInt64})
-
-  of tyFloat32: greater({tyFloat64, tyFloat128})
-  of tyFloat64: greater({tyFloat128})
-  else: discard
+when false:
+  proc maxNumericType(prev, candidate: PType): PType =
+    let c = candidate.skipTypes({tyRange})
+    template greater(s) =
+      if c.kind in s: result = c
+    case prev.kind
+    of tyInt: greater({tyInt64})
+    of tyInt8: greater({tyInt, tyInt16, tyInt32, tyInt64})
+    of tyInt16: greater({tyInt, tyInt32, tyInt64})
+    of tyInt32: greater({tyInt64})
+
+    of tyUInt: greater({tyUInt64})
+    of tyUInt8: greater({tyUInt, tyUInt16, tyUInt32, tyUInt64})
+    of tyUInt16: greater({tyUInt, tyUInt32, tyUInt64})
+    of tyUInt32: greater({tyUInt64})
+
+    of tyFloat32: greater({tyFloat64, tyFloat128})
+    of tyFloat64: greater({tyFloat128})
+    else: discard
 
 proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
                  flags: TTypeRelFlags = {}): TTypeRelation =
@@ -1145,12 +1146,12 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
           fRange = prev
       let ff = f.sons[1].skipTypes({tyTypeDesc})
       let aa = a.sons[1].skipTypes({tyTypeDesc})
-      
+
       if f.sons[0].kind != tyGenericParam and aa.kind == tyEmpty:
-        result = isGeneric  
+        result = isGeneric
       else:
         result = typeRel(c, ff, aa)
-     
+
       if result < isGeneric:
         if nimEnableCovariance and
            trNoCovariance notin flags and
@@ -1631,13 +1632,15 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
       # Special type binding rule for numeric types.
       # See section "Generic type inference for numeric types" of the
       # manual for further details:
-      let rebinding = maxNumericType(x.skipTypes({tyRange}), a)
-      if rebinding != nil:
-        put(c, f, rebinding)
-        result = isGeneric
-      else:
-        result = typeRel(c, x, a) # check if it fits
-        if result > isGeneric: result = isGeneric
+      when false:
+        let rebinding = maxNumericType(x.skipTypes({tyRange}), a)
+        if rebinding != nil:
+          put(c, f, rebinding)
+          result = isGeneric
+        else:
+          discard
+      result = typeRel(c, x, a) # check if it fits
+      if result > isGeneric: result = isGeneric
   of tyStatic:
     let prev = PType(idTableGet(c.bindings, f))
     if prev == nil:
diff --git a/doc/manual/generics.txt b/doc/manual/generics.txt
index 30055f035..4c908fefe 100644
--- a/doc/manual/generics.txt
+++ b/doc/manual/generics.txt
@@ -713,29 +713,3 @@ definition):
 But a ``bind`` is rarely useful because symbol binding from the definition
 scope is the default.
 
-
-Generic type inference for numeric types
-----------------------------------------
-
-A `numeric`:idx: type is any signed, unsigned integer type, floating point
-type or a subrange thereof. Let ``maxNumericType(T1, T2)`` be the "greater"
-type of ``T1`` and ``T2``, that is the type that uses more bits. For
-example ``maxNumericType(int32, int64) == int64``. ``maxNumericType`` is only
-defined for numeric types of the same class (signed, unsigned, floating point).
-``maxNumericType`` strips away subranges,
-``maxNumericType(subrangeof(int16), int8)`` produces ``int16`` not its
-subrange. The definition ``maxNumericType`` is extended to take a variable
-number of arguments in the obvious way;
-``maxNumericType(x, y, z) == maxNumericType(maxNumericType(x, y), z)``.
-
-A generic type parameter ``T`` that is bound to multiple numeric types ``N1``,
-``N2``, ``N3``, ... during type checking is inferred to
-be ``maxNumericType(N1, N2, N3, ...)``. This special type inference rule ensures
-that the builtin arithmetic operators can be written in an intuitive way:
-
-.. code-block:: nim
-  proc `@`[T: int|int16|int32](x, y: T): T
-
-  4'i32 @ 6'i64 # inferred to be of type ``int64``
-
-  4'i64 @ 6'i32 # inferred to be of type ``int64``
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index 777beabc3..c97846f92 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -955,6 +955,17 @@ proc `[]=`*[A](t: var CountTable[A], key: A, val: int) =
     #t.data[h].key = key
     #t.data[h].val = val
 
+proc inc*[A](t: var CountTable[A], key: A, val = 1) =
+  ## increments `t[key]` by `val`.
+  var index = rawGet(t, key)
+  if index >= 0:
+    inc(t.data[index].val, val)
+    if t.data[index].val == 0: dec(t.counter)
+  else:
+    if mustRehash(len(t.data), t.counter): enlarge(t)
+    rawInsert(t, t.data, key, val)
+    inc(t.counter)
+
 proc initCountTable*[A](initialSize=64): CountTable[A] =
   ## creates a new count table that is empty.
   ##
@@ -969,7 +980,7 @@ proc toCountTable*[A](keys: openArray[A]): CountTable[A] =
   ## creates a new count table with every key in `keys` having a count
   ## of how many times it occurs in `keys`.
   result = initCountTable[A](rightSize(keys.len))
-  for key in items(keys): result.inc key
+  for key in items(keys): result.inc(key)
 
 proc `$`*[A](t: CountTable[A]): string =
   ## The `$` operator for count tables.
@@ -980,17 +991,6 @@ proc `==`*[A](s, t: CountTable[A]): bool =
   ## contain the same keys with the same count. Insert order does not matter.
   equalsImpl(s, t)
 
-proc inc*[A](t: var CountTable[A], key: A, val = 1) =
-  ## increments `t[key]` by `val`.
-  var index = rawGet(t, key)
-  if index >= 0:
-    inc(t.data[index].val, val)
-    if t.data[index].val == 0: dec(t.counter)
-  else:
-    if mustRehash(len(t.data), t.counter): enlarge(t)
-    rawInsert(t, t.data, key, val)
-    inc(t.counter)
-
 proc smallest*[A](t: CountTable[A]): tuple[key: A, val: int] =
   ## returns the (key,val)-pair with the smallest `val`. Efficiency: O(n)
   assert t.len > 0
@@ -1088,6 +1088,10 @@ proc `[]=`*[A](t: CountTableRef[A], key: A, val: int) =
   assert val > 0
   t[][key] = val
 
+proc inc*[A](t: CountTableRef[A], key: A, val = 1) =
+  ## increments `t[key]` by `val`.
+  t[].inc(key, val)
+
 proc newCountTable*[A](initialSize=64): CountTableRef[A] =
   ## creates a new count table that is empty.
   ##
@@ -1098,9 +1102,10 @@ proc newCountTable*[A](initialSize=64): CountTableRef[A] =
   result[] = initCountTable[A](initialSize)
 
 proc newCountTable*[A](keys: openArray[A]): CountTableRef[A] =
-  ## creates a new count table with every key in `keys` having a count of 1.
+  ## creates a new count table with every key in `keys` having a count
+  ## of how many times it occurs in `keys`.
   result = newCountTable[A](rightSize(keys.len))
-  for key in items(keys): result[key] = 1
+  for key in items(keys): result.inc(key)
 
 proc `$`*[A](t: CountTableRef[A]): string =
   ## The `$` operator for count tables.
@@ -1114,10 +1119,6 @@ proc `==`*[A](s, t: CountTableRef[A]): bool =
   elif isNil(t): result = false
   else: result = s[] == t[]
 
-proc inc*[A](t: CountTableRef[A], key: A, val = 1) =
-  ## increments `t[key]` by `val`.
-  t[].inc(key, val)
-
 proc smallest*[A](t: CountTableRef[A]): (A, int) =
   ## returns the (key,val)-pair with the smallest `val`. Efficiency: O(n)
   t[].smallest
@@ -1316,7 +1317,6 @@ when isMainModule:
     assert a == b
     assert a == c
 
-
   block: #6250
     let
       a = {3: 1}.toOrderedTable
@@ -1332,6 +1332,5 @@ when isMainModule:
     assert((b == a) == true)
 
   block: # CountTable.smallest
-    var t = initCountTable[int]()
-    for v in items([0, 0, 5, 5, 5]): t.inc(v)
+    let t = toCountTable([0, 0, 5, 5, 5])
     doAssert t.smallest == (0, 2)
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index f81e80766..648481ca5 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -507,7 +507,7 @@ proc request*(url: string, httpMethod: string, extraHeaders = "",
       port = net.Port(443)
     else:
       raise newException(HttpRequestError,
-                "SSL support is not available. Cannot connect over SSL.")
+                "SSL support is not available. Cannot connect over SSL. Compile with -d:ssl to enable.")
   if r.port != "":
     port = net.Port(r.port.parseInt)
 
@@ -540,7 +540,8 @@ proc request*(url: string, httpMethod: string, extraHeaders = "",
                            "so a secure connection could not be established.")
       sslContext.wrapConnectedSocket(s, handshakeAsClient, hostUrl.hostname)
     else:
-      raise newException(HttpRequestError, "SSL support not available. Cannot connect via proxy over SSL")
+      raise newException(HttpRequestError, "SSL support not available. Cannot " &
+                         "connect via proxy over SSL. Compile with -d:ssl to enable.")
   else:
     if timeout == -1:
       s.connect(r.hostname, port)
@@ -1087,7 +1088,7 @@ proc newConnection(client: HttpClient | AsyncHttpClient,
 
     if isSsl and not defined(ssl):
       raise newException(HttpRequestError,
-        "SSL support is not available. Cannot connect over SSL.")
+        "SSL support is not available. Cannot connect over SSL. Compile with -d:ssl to enable.")
 
     if client.connected:
       client.close()
@@ -1137,7 +1138,7 @@ proc newConnection(client: HttpClient | AsyncHttpClient,
           client.socket, handshakeAsClient, url.hostname)
       else:
         raise newException(HttpRequestError,
-        "SSL support is not available. Cannot connect over SSL.")
+        "SSL support is not available. Cannot connect over SSL. Compile with -d:ssl to enable.")
 
     # May be connected through proxy but remember actual URL being accessed
     client.currentURL = url
@@ -1333,4 +1334,4 @@ proc downloadFile*(client: AsyncHttpClient, url: string,
   finally:
     result.addCallback(
       proc () = client.getBody = true
-    )
\ No newline at end of file
+    )
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index 99d868847..af9eea51a 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -430,8 +430,14 @@ when defineSsl:
       raise newException(SSLError, "No error reported.")
     if err == -1:
       raiseOSError(osLastError())
-    var errStr = ErrErrorString(err, nil)
-    raise newException(SSLError, $errStr)
+    var errStr = $ErrErrorString(err, nil)
+    case err
+    of 336032814, 336032784:
+      errStr = "Please upgrade your OpenSSL library, it does not support the " &
+               "necessary protocols. OpenSSL error is: " & errStr
+    else:
+      discard
+    raise newException(SSLError, errStr)
 
   proc getExtraData*(ctx: SSLContext, index: int): RootRef =
     ## Retrieves arbitrary data stored inside SSLContext.
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index 1625845d1..c1c727fc6 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -306,7 +306,7 @@ proc execProcesses*(cmds: openArray[string],
             raiseOSError(err)
 
       if rexit >= 0:
-        result = max(result, q[rexit].peekExitCode())
+        result = max(result, abs(q[rexit].peekExitCode()))
         if afterRunEvent != nil: afterRunEvent(rexit, q[rexit])
         close(q[rexit])
         if i < len(cmds):
@@ -331,7 +331,7 @@ proc execProcesses*(cmds: openArray[string],
       if beforeRunEvent != nil:
         beforeRunEvent(i)
       var p = startProcess(cmds[i], options=options + {poEvalCommand})
-      result = max(waitForExit(p), result)
+      result = max(abs(waitForExit(p)), result)
       if afterRunEvent != nil: afterRunEvent(i, p)
       close(p)
 
diff --git a/lib/pure/parsecsv.nim b/lib/pure/parsecsv.nim
index 071858b7c..358ce829d 100644
--- a/lib/pure/parsecsv.nim
+++ b/lib/pure/parsecsv.nim
@@ -32,7 +32,7 @@
 ##   import parsecsv
 ##   import os
 ##   # Prepare a file
-##   var content = """One,Two,Three,Four
+##   let content = """One,Two,Three,Four
 ##   1,2,3,4
 ##   10,20,30,40
 ##   100,200,300,400
@@ -123,7 +123,7 @@ proc parseField(my: var CsvParser, a: var string) =
   if buf[pos] == my.quote and my.quote != '\0':
     inc(pos)
     while true:
-      var c = buf[pos]
+      let c = buf[pos]
       if c == '\0':
         my.bufpos = pos # can continue after exception?
         error(my, pos, my.quote & " expected")
@@ -153,7 +153,7 @@ proc parseField(my: var CsvParser, a: var string) =
           inc(pos)
   else:
     while true:
-      var c = buf[pos]
+      let c = buf[pos]
       if c == my.sep: break
       if c in {'\c', '\l', '\0'}: break
       add(a, c)
@@ -171,9 +171,9 @@ proc readRow*(my: var CsvParser, columns = 0): bool =
   ##
   ## Blank lines are skipped.
   var col = 0 # current column
-  var oldpos = my.bufpos
+  let oldpos = my.bufpos
   while my.buf[my.bufpos] != '\0':
-    var oldlen = my.row.len
+    let oldlen = my.row.len
     if oldlen < col+1:
       setLen(my.row, col+1)
       my.row[col] = ""
@@ -208,16 +208,16 @@ proc close*(my: var CsvParser) {.inline.} =
 proc readHeaderRow*(my: var CsvParser) =
   ## Reads the first row and creates a look-up table for column numbers
   ## See also `rowEntry <#rowEntry.CsvParser.string>`_.
-  var present = my.readRow()
+  let present = my.readRow()
   if present:
     my.headers = my.row
 
-proc rowEntry*(my: var CsvParser, entry: string): string =
-  ## Reads a specified `entry` from the current row.
+proc rowEntry*(my: var CsvParser, entry: string): var string =
+  ## Acceses a specified `entry` from the current row.
   ##
   ## Assumes that `readHeaderRow <#readHeaderRow.CsvParser>`_ has already been
   ## called.
-  var index = my.headers.find(entry)
+  let index = my.headers.find(entry)
   if index >= 0:
     result = my.row[index]
 
@@ -237,14 +237,14 @@ when isMainModule:
   import os
   import strutils
   block: # Tests for reading the header row
-    var content = "One,Two,Three,Four\n1,2,3,4\n10,20,30,40,\n100,200,300,400\n"
+    let content = "One,Two,Three,Four\n1,2,3,4\n10,20,30,40,\n100,200,300,400\n"
     writeFile("temp.csv", content)
 
     var p: CsvParser
     p.open("temp.csv")
     p.readHeaderRow()
     while p.readRow():
-      var zeros = repeat('0', p.currRow-2)
+      let zeros = repeat('0', p.currRow-2)
       doAssert p.rowEntry("One") == "1" & zeros
       doAssert p.rowEntry("Two") == "2" & zeros
       doAssert p.rowEntry("Three") == "3" & zeros
diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim
index 032d3360f..6ed04c0d8 100644
--- a/lib/pure/terminal.nim
+++ b/lib/pure/terminal.nim
@@ -372,7 +372,7 @@ proc cursorForward*(f: File, count=1) =
     inc(p.x, count)
     setCursorPos(h, p.x, p.y)
   else:
-    f.write("{stylePrefix}{count}C")
+    f.write(fmt"{stylePrefix}{count}C")
 
 proc cursorBackward*(f: File, count=1) =
   ## Moves the cursor backward by `count` columns.
@@ -382,7 +382,7 @@ proc cursorBackward*(f: File, count=1) =
     dec(p.x, count)
     setCursorPos(h, p.x, p.y)
   else:
-    f.write("{stylePrefix}{count}D")
+    f.write(fmt"{stylePrefix}{count}D")
 
 when true:
   discard
diff --git a/lib/system.nim b/lib/system.nim
index 6815932e2..2b2ce7008 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1917,7 +1917,7 @@ proc `$` *(x: float): string {.magic: "FloatToStr", noSideEffect.}
 proc `$` *(x: bool): string {.magic: "BoolToStr", noSideEffect.}
   ## The stringify operator for a boolean argument. Returns `x`
   ## converted to the string "false" or "true".
-#
+
 proc `$` *(x: char): string {.magic: "CharToStr", noSideEffect.}
   ## The stringify operator for a character argument. Returns `x`
   ## converted to a string.
diff --git a/tests/casestmt/tduplicates.nim b/tests/casestmt/tduplicates.nim
new file mode 100644
index 000000000..f9fc1cc26
--- /dev/null
+++ b/tests/casestmt/tduplicates.nim
@@ -0,0 +1,50 @@
+discard """
+  output: '''
+OK
+OK
+OK
+  '''
+"""
+
+type Kind = enum A, B
+var k = A
+
+template reject(b) =
+  static: doAssert(not compiles(b))
+
+reject:
+    var i = 2
+    case i
+    of [1, 1]: discard
+    else: discard
+
+reject:
+    var i = 2
+    case i
+    of 1, { 1..2 }: discard
+    else: discard
+
+reject:
+    var i = 2
+    case i
+    of { 1, 1 }: discard
+    of { 1, 1 }: discard
+    else: discard
+
+reject:
+    case k
+    of [A, A]: discard
+
+var i = 2
+case i
+of { 1, 1 }: discard
+of { 2, 2 }: echo "OK"
+else: discard
+
+case i
+of { 10..30, 15..25, 5..15, 25..35 }: discard
+else: echo "OK"
+
+case k
+of {A, A..A}: echo "OK"
+of B: discard
\ No newline at end of file
diff --git a/tests/cpp/tcppraise.nim b/tests/cpp/tcppraise.nim
index 7db9c0cfa..f359a2e8b 100644
--- a/tests/cpp/tcppraise.nim
+++ b/tests/cpp/tcppraise.nim
@@ -3,7 +3,9 @@ discard """
   output: '''foo
 bar
 Need odd and >= 3 digits##
-baz'''
+baz
+caught
+'''
 """
 
 # bug #1888
@@ -15,3 +17,21 @@ try:
 except ValueError:
   echo getCurrentExceptionMsg(), "##"
 echo "baz"
+
+
+# bug 7232
+try:
+ discard
+except KeyError, ValueError:
+  echo "except handler" # should not be invoked
+
+
+#bug 7239
+try:
+  try:
+    raise newException(ValueError, "asdf")
+  except KeyError, ValueError:
+    raise
+except:
+  echo "caught"
+
diff --git a/tests/generics/tspecial_numeric_inference.nim b/tests/generics/tspecial_numeric_inference.nim
index d93544ba4..41a84a5e9 100644
--- a/tests/generics/tspecial_numeric_inference.nim
+++ b/tests/generics/tspecial_numeric_inference.nim
@@ -1,12 +1,21 @@
 discard """
-  output: '''int64
-int64'''
+  output: '''false'''
 """
 
-import typetraits
+when false:
+  import typetraits
 
-proc `@`[T: SomeInteger](x, y: T): T = x
+  proc `@`[T: SomeInteger](x, y: T): T = x
 
-echo(type(5'i64 @ 6'i32))
+  echo(type(5'i64 @ 6'i32))
 
-echo(type(5'i32 @ 6'i64))
+  echo(type(5'i32 @ 6'i64))
+
+import sets
+# bug #7247
+type
+  n8 = range[0'i8..127'i8]
+
+var tab = initSet[n8]()
+
+echo tab.contains(8)
diff --git a/tests/iter/titer2.nim b/tests/iter/titer2.nim
index 4a7f76883..f60aed73a 100644
--- a/tests/iter/titer2.nim
+++ b/tests/iter/titer2.nim
@@ -2,7 +2,12 @@ discard """
   output: '''true
 3
 4
-5'''
+5
+0
+1
+2
+3
+4'''
   cmd: "nim $target --gc:none --hints:on --warnings:off $options $file"
 """
 
@@ -55,3 +60,7 @@ echo "true"
 # bug #1560
 for i in @[3, 4, 5]:
   echo($i)
+
+# bug #6992
+for i in 0 ..< 5u32:
+  echo i
diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim
index 918de881f..06f5fec7d 100644
--- a/tests/testament/tester.nim
+++ b/tests/testament/tester.nim
@@ -294,7 +294,6 @@ proc compilerOutputTests(test: TTest, target: TTarget, given: var TSpec,
 proc testSpec(r: var TResults, test: TTest, target = targetC) =
   let tname = test.name.addFileExt(".nim")
   #echo "TESTING ", tname
-  inc(r.total)
   var expected: TSpec
   if test.action != actionRunNoSpec:
     expected = parseSpec(tname)
@@ -305,12 +304,14 @@ proc testSpec(r: var TResults, test: TTest, target = targetC) =
   if expected.err == reIgnored:
     r.addResult(test, target, "", "", reIgnored)
     inc(r.skipped)
+    inc(r.total)
     return
 
   if expected.targets == {}:
     expected.targets.incl(target)
 
   for target in expected.targets:
+    inc(r.total)
     if target notin targets:
       r.addResult(test, target, "", "", reIgnored)
       inc(r.skipped)
@@ -490,7 +491,7 @@ proc main() =
     else: echo r, r.data
   backend.close()
   var failed = r.total - r.passed - r.skipped
-  if failed > 0:
+  if failed != 0:
     echo "FAILURE! total: ", r.total, " passed: ", r.passed, " skipped: ", r.skipped
     quit(QuitFailure)