summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--changelog.md3
-rw-r--r--compiler/cgen.nim8
-rw-r--r--compiler/extccomp.nim2
-rw-r--r--compiler/jsgen.nim4
-rw-r--r--compiler/passes.nim4
-rw-r--r--compiler/renderer.nim1
-rw-r--r--compiler/sem.nim10
-rw-r--r--compiler/semexprs.nim6
-rw-r--r--compiler/transf.nim2
-rw-r--r--compiler/vmgen.nim47
-rw-r--r--doc/lib.rst4
-rw-r--r--doc/manual/stmts.txt4
-rw-r--r--koch.nim2
-rw-r--r--lib/nimbase.h13
-rw-r--r--lib/posix/posix_other.nim2
-rw-r--r--lib/pure/asyncdispatch.nim2
-rw-r--r--lib/pure/collections/sharedlist.nim15
-rw-r--r--lib/pure/collections/sharedtables.nim20
-rw-r--r--lib/pure/memfiles.nim11
-rw-r--r--lib/pure/rationals.nim11
-rw-r--r--lib/pure/times.nim21
-rw-r--r--lib/system.nim12
-rw-r--r--lib/system/gc.nim2
-rw-r--r--lib/system/gc2.nim2
-rw-r--r--lib/system/gc_ms.nim2
-rw-r--r--tests/collections/ttables.nim3
-rw-r--r--tests/stdlib/tmemfiles2.nim2
-rw-r--r--tests/testament/tester.nim17
-rw-r--r--tests/vm/tcastint.nim120
-rw-r--r--tools/nimgrep.nim46
-rw-r--r--web/website.ini1
31 files changed, 301 insertions, 98 deletions
diff --git a/changelog.md b/changelog.md
index 1c5848ce8..21ab2b87a 100644
--- a/changelog.md
+++ b/changelog.md
@@ -187,3 +187,6 @@ let
   mySeq = @[1, 2, 1, 3, 1, 4]
   myCounter = mySeq.toCountTable()
 ```
+
+- Added support for casting between integers of same bitsize in VM (compile time and nimscript).
+  This allow to among other things to reinterpret signed integers as unsigned.
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 217138dd0..573a14927 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -1258,7 +1258,7 @@ proc resetModule*(m: BModule) =
 
   # indicate that this is now cached module
   # the cache will be invalidated by nullifying gModules
-  m.fromCache = true
+  #m.fromCache = true
   m.g = nil
 
   # we keep only the "merge info" information for the module
@@ -1390,7 +1390,7 @@ proc writeModule(m: BModule, pending: bool) =
   # generate code for the init statements of the module:
   let cfile = getCFile(m)
 
-  if not m.fromCache or optForceFullMake in gGlobalOptions:
+  if m.rd == nil or optForceFullMake in gGlobalOptions:
     genInitCode(m)
     finishTypeDescriptions(m)
     if sfMainModule in m.module.flags:
@@ -1465,10 +1465,10 @@ proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
   if g.generatedHeader != nil: finishModule(g.generatedHeader)
   while g.forwardedProcsCounter > 0:
     for m in cgenModules(g):
-      if not m.fromCache:
+      if m.rd == nil:
         finishModule(m)
   for m in cgenModules(g):
-    if m.fromCache:
+    if m.rd != nil:
       m.updateCachedModule
     else:
       m.writeModule(pending=true)
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index 5299b2dbf..62990593d 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -253,7 +253,7 @@ compiler tcc:
     compilerExe: "tcc",
     cppCompiler: "",
     compileTmpl: "-c $options $include -o $objfile $file",
-    buildGui: "UNAVAILABLE!",
+    buildGui: "-Wl,-subsystem=gui",
     buildDll: " -shared",
     buildLib: "", # XXX: not supported yet
     linkerExe: "tcc",
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 65a6a5dae..dac2de746 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -2051,10 +2051,10 @@ proc genConv(p: PProc, n: PNode, r: var TCompRes) =
     return
   case dest.kind:
   of tyBool:
-    r.res = "(($1)? 1:0)" % [r.res]
+    r.res = "(!!($1))" % [r.res]
     r.kind = resExpr
   of tyInt:
-    r.res = "($1|0)" % [r.res]
+    r.res = "(($1)|0)" % [r.res]
   else:
     # TODO: What types must we handle here?
     discard
diff --git a/compiler/passes.nim b/compiler/passes.nim
index b84fe2f4d..29b27627d 100644
--- a/compiler/passes.nim
+++ b/compiler/passes.nim
@@ -18,7 +18,7 @@ import
 
 type
   TPassContext* = object of RootObj # the pass's context
-    fromCache*: bool  # true if created by "openCached"
+    rd*: PRodReader  # != nil if created by "openCached"
 
   PPassContext* = ref TPassContext
 
@@ -118,7 +118,7 @@ proc openPassesCached(g: ModuleGraph; a: var TPassContextArray, module: PSym,
     if not isNil(gPasses[i].openCached):
       a[i] = gPasses[i].openCached(g, module, rd)
       if a[i] != nil:
-        a[i].fromCache = true
+        a[i].rd = rd
     else:
       a[i] = nil
 
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index d4b401c02..6735cc1ce 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -719,6 +719,7 @@ proc gcase(g: var TSrcGen, n: PNode) =
   var c: TContext
   initContext(c)
   var length = sonsLen(n)
+  if length == 0: return
   var last = if n.sons[length-1].kind == nkElse: -2 else: -1
   if longMode(g, n, 0, last): incl(c.flags, rfLongMode)
   putWithSpace(g, tkCase, "case")
diff --git a/compiler/sem.nim b/compiler/sem.nim
index ababbd303..1098e9961 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -74,7 +74,7 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
     localError(arg.info, errExprXHasNoType,
                renderTree(arg, {renderNoComments}))
     # error correction:
-    result = copyNode(arg)
+    result = copyTree(arg)
     result.typ = formal
   else:
     result = indexTypesMatch(c, formal, arg.typ, arg)
@@ -168,9 +168,9 @@ proc commonType*(x, y: PType): PType =
 proc endsInNoReturn(n: PNode): bool =
   # check if expr ends in raise exception or call of noreturn proc
   var it = n
-  while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0: 
+  while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0:
     it = it.lastSon
-  result = it.kind == nkRaiseStmt or 
+  result = it.kind == nkRaiseStmt or
     it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
 
 proc commonType*(x: PType, y: PNode): PType =
@@ -501,6 +501,8 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
 
 proc myOpenCached(graph: ModuleGraph; module: PSym; rd: PRodReader): PPassContext =
   result = myOpen(graph, module, rd.cache)
+
+proc replayMethodDefs(graph: ModuleGraph; rd: PRodReader) =
   for m in items(rd.methods): methodDef(graph, m, true)
 
 proc isImportSystemStmt(n: PNode): bool =
@@ -607,6 +609,8 @@ proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode =
   addCodeForGenerics(c, result)
   if c.module.ast != nil:
     result.add(c.module.ast)
+  if c.rd != nil:
+    replayMethodDefs(graph, c.rd)
   popOwner(c)
   popProcCon(c)
   if c.runnableExamples != nil: testExamples(c)
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index a0f519820..51e75e91f 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1425,11 +1425,7 @@ proc semProcBody(c: PContext, n: PNode): PNode =
   openScope(c)
   result = semExpr(c, n)
   if c.p.resultSym != nil and not isEmptyType(result.typ):
-    # transform ``expr`` to ``result = expr``, but not if the expr is already
-    # ``result``:
-    if result.kind == nkSym and result.sym == c.p.resultSym:
-      discard
-    elif result.kind == nkNilLit:
+    if result.kind == nkNilLit:
       # or ImplicitlyDiscardable(result):
       # new semantic: 'result = x' triggers the void context
       result.typ = nil
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 6bc809fd2..f8f7f8746 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -914,7 +914,7 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
   # Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
   # this step! We have to rely that the semantic pass transforms too errornous
   # nodes into an empty node.
-  if c.fromCache or nfTransf in n.flags: return n
+  if c.rd != nil or nfTransf in n.flags: return n
   pushTransCon(c, newTransCon(owner))
   result = PNode(transform(c, n))
   popTransCon(c)
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 3790a8392..17878b656 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -30,7 +30,7 @@
 import
   strutils, ast, astalgo, types, msgs, renderer, vmdef,
   trees, intsets, rodread, magicsys, options, lowerings
-
+import platform
 from os import splitFile
 
 when hasFFI:
@@ -761,6 +761,49 @@ proc genCard(c: PCtx; n: PNode; dest: var TDest) =
   c.gABC(n, opcCard, dest, tmp)
   c.freeTemp(tmp)
 
+proc genIntCast(c: PCtx; n: PNode; dest: var TDest) =
+  const allowedIntegers = {tyInt..tyInt64, tyUInt..tyUInt64, tyChar}
+  var signedIntegers = {tyInt8..tyInt32}
+  var unsignedIntegers = {tyUInt8..tyUInt32, tyChar}
+  let src = n.sons[1].typ.skipTypes(abstractRange)#.kind
+  let dst = n.sons[0].typ.skipTypes(abstractRange)#.kind
+  let src_size = src.getSize
+
+  if platform.intSize < 8:
+    signedIntegers.incl(tyInt)
+    unsignedIntegers.incl(tyUInt)
+  if src_size == dst.getSize and src.kind in allowedIntegers and
+                                 dst.kind in allowedIntegers:
+    let tmp = c.genx(n.sons[1])
+    var tmp2 = c.getTemp(n.sons[1].typ)
+    let tmp3 = c.getTemp(n.sons[1].typ)
+    if dest < 0: dest = c.getTemp(n[0].typ)
+    proc mkIntLit(ival: int): int =
+      result = genLiteral(c, newIntTypeNode(nkIntLit, ival, getSysType(tyInt)))
+    if src.kind in unsignedIntegers and dst.kind in signedIntegers:
+      # cast unsigned to signed integer of same size
+      # signedVal = (unsignedVal xor offset) -% offset
+      let offset = 1 shl (src_size * 8 - 1)
+      c.gABx(n, opcLdConst, tmp2, mkIntLit(offset))
+      c.gABC(n, opcBitxorInt, tmp3, tmp, tmp2)
+      c.gABC(n, opcSubInt, dest, tmp3, tmp2)
+    elif src.kind in signedIntegers and dst.kind in unsignedIntegers:
+      # cast signed to unsigned integer of same size
+      # unsignedVal = (offset +% signedVal +% 1) and offset
+      let offset = (1 shl (src_size * 8))  - 1
+      c.gABx(n, opcLdConst, tmp2, mkIntLit(offset))
+      c.gABx(n, opcLdConst, dest, mkIntLit(offset+1))
+      c.gABC(n, opcAddu, tmp3, tmp, dest)
+      c.gABC(n, opcNarrowU, tmp3, TRegister(src_size*8))
+      c.gABC(n, opcBitandInt, dest, tmp3, tmp2)
+    else:
+      c.gABC(n, opcAsgnInt, dest, tmp)
+    c.freeTemp(tmp)
+    c.freeTemp(tmp2)
+    c.freeTemp(tmp3)
+  else:
+    globalError(n.info, errGenerated, "VM is only allowed to 'cast' between integers of same size")
+
 proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   case m
   of mAnd: c.genAndOr(n, opcFJmp, dest)
@@ -1844,7 +1887,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     if allowCast in c.features:
       genConv(c, n, n.sons[1], dest, opcCast)
     else:
-      globalError(n.info, errGenerated, "VM is not allowed to 'cast'")
+      genIntCast(c, n, dest)
   of nkTypeOfExpr:
     genTypeLit(c, n.typ, dest)
   of nkComesFrom:
diff --git a/doc/lib.rst b/doc/lib.rst
index 58dedc49c..755c11899 100644
--- a/doc/lib.rst
+++ b/doc/lib.rst
@@ -92,6 +92,10 @@ Collections and algorithms
 * `sequtils <sequtils.html>`_
   This module implements operations for the built-in seq type
   which were inspired by functional programming languages.
+* `sharedtables <sharedtables.html>`_
+  Nim shared hash table support. Contains shared tables.
+* `sharedlist <sharedlist.html>`_
+  Nim shared linked list support. Contains shared singly linked list.
 
 
 String handling
diff --git a/doc/manual/stmts.txt b/doc/manual/stmts.txt
index b24ec3b4a..721b5cff8 100644
--- a/doc/manual/stmts.txt
+++ b/doc/manual/stmts.txt
@@ -296,6 +296,10 @@ empty ``discard`` statement should be used.
 For non ordinal types it is not possible to list every possible value and so
 these always require an ``else`` part.
 
+As case statements perform compile-time exhaustiveness checks, the value in 
+every ``of`` branch must be known at compile time. This fact is also exploited
+to generate more performant code.
+
 As a special semantic extension, an expression in an ``of`` branch of a case
 statement may evaluate to a set or array constructor; the set or array is then
 expanded into a list of its elements:
diff --git a/koch.nim b/koch.nim
index 3ef9a340a..7bb7ea402 100644
--- a/koch.nim
+++ b/koch.nim
@@ -260,7 +260,7 @@ proc buildTools(latest: bool) =
       " nimsuggest/nimsuggest.nim"
 
   let nimgrepExe = "bin/nimgrep".exe
-  nimexec "c -o:" & nimgrepExe & " tools/nimgrep.nim"
+  nimexec "c -d:release -o:" & nimgrepExe & " tools/nimgrep.nim"
   when defined(windows): buildVccTool()
 
   #nimexec "c -o:" & ("bin/nimresolve".exe) & " tools/nimresolve.nim"
diff --git a/lib/nimbase.h b/lib/nimbase.h
index b12d8e34d..31075bbd2 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -400,11 +400,11 @@ typedef struct TStringDesc* string;
 
 // NAN definition copied from math.h included in the Windows SDK version 10.0.14393.0
 #ifndef NAN
-#ifndef _HUGE_ENUF
-#define _HUGE_ENUF  1e+300  // _HUGE_ENUF*_HUGE_ENUF must overflow
-#endif
-#define NAN_INFINITY ((float)(_HUGE_ENUF * _HUGE_ENUF))
-#define NAN ((float)(NAN_INFINITY * 0.0F))
+#  ifndef _HUGE_ENUF
+#    define _HUGE_ENUF  1e+300  // _HUGE_ENUF*_HUGE_ENUF must overflow
+#  endif
+#  define NAN_INFINITY ((float)(_HUGE_ENUF * _HUGE_ENUF))
+#  define NAN ((float)(NAN_INFINITY * 0.0F))
 #endif
 
 #ifndef INF
@@ -482,7 +482,6 @@ static inline void GCGuard (void *ptr) { asm volatile ("" :: "X" (ptr)); }
    On disagreement, your C compiler will say something like:
    "error: 'Nim_and_C_compiler_disagree_on_target_architecture' declared as an array with a negative size" */
 typedef int Nim_and_C_compiler_disagree_on_target_architecture[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8 ? 1 : -1];
-#endif
 
 #ifdef  __cplusplus
 #  define NIM_EXTERNC extern "C"
@@ -509,3 +508,5 @@ extern Libc::Env *genodeEnv;
 /* Compile with -d:checkAbi and a sufficiently C11:ish compiler to enable */
 #define NIM_CHECK_SIZE(typ, sz) \
   _Static_assert(sizeof(typ) == sz, "Nim & C disagree on type size")
+
+#endif /* NIMBASE_H */
diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim
index e552bf807..01bc1c1e5 100644
--- a/lib/posix/posix_other.nim
+++ b/lib/posix/posix_other.nim
@@ -34,7 +34,7 @@ type
 {.deprecated: [TSocketHandle: SocketHandle].}
 
 type
-  Time* {.importc: "time_t", header: "<time.h>".} = distinct int
+  Time* {.importc: "time_t", header: "<time.h>".} = distinct clong
 
   Timespec* {.importc: "struct timespec",
                header: "<time.h>", final, pure.} = object ## struct timespec
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index b62cf2e9b..42ffa236c 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -1487,7 +1487,7 @@ proc drain*(timeout = 500) =
   ## if there are no pending operations. In contrast to ``poll`` this
   ## processes as many events as are available.
   if runOnce(timeout):
-    while runOnce(0): discard
+    while hasPendingOperations() and runOnce(0): discard
 
 proc poll*(timeout = 500) =
   ## Waits for completion events and processes them. Raises ``ValueError``
diff --git a/lib/pure/collections/sharedlist.nim b/lib/pure/collections/sharedlist.nim
index e93ceb02f..b3e677b79 100644
--- a/lib/pure/collections/sharedlist.nim
+++ b/lib/pure/collections/sharedlist.nim
@@ -73,10 +73,10 @@ proc add*[A](x: var SharedList[A]; y: A) =
     node.d[node.dataLen] = y
     inc(node.dataLen)
 
-proc initSharedList*[A](): SharedList[A] =
-  initLock result.lock
-  result.head = nil
-  result.tail = nil
+proc init*[A](t: var SharedList[A]) =
+  initLock t.lock
+  t.head = nil
+  t.tail = nil
 
 proc clear*[A](t: var SharedList[A]) =
   withLock(t):
@@ -92,4 +92,11 @@ proc deinitSharedList*[A](t: var SharedList[A]) =
   clear(t)
   deinitLock t.lock
 
+proc initSharedList*[A](): SharedList[A] {.deprecated.} =
+  ## Deprecated. Use `init` instead.
+  ## This is not posix compliant, may introduce undefined behavior.
+  initLock result.lock
+  result.head = nil
+  result.tail = nil
+
 {.pop.}
diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim
index 211a6ce6a..4f311af87 100644
--- a/lib/pure/collections/sharedtables.nim
+++ b/lib/pure/collections/sharedtables.nim
@@ -192,19 +192,29 @@ proc del*[A, B](t: var SharedTable[A, B], key: A) =
   withLock t:
     delImpl()
 
-proc initSharedTable*[A, B](initialSize=64): SharedTable[A, B] =
+proc init*[A, B](t: var SharedTable[A, B], initialSize=64) =
   ## creates a new hash table that is empty.
   ##
   ## `initialSize` needs to be a power of two. If you need to accept runtime
   ## values for this you could use the ``nextPowerOfTwo`` proc from the
   ## `math <math.html>`_ module or the ``rightSize`` proc from this module.
   assert isPowerOfTwo(initialSize)
-  result.counter = 0
-  result.dataLen = initialSize
-  result.data = cast[KeyValuePairSeq[A, B]](allocShared0(
+  t.counter = 0
+  t.dataLen = initialSize
+  t.data = cast[KeyValuePairSeq[A, B]](allocShared0(
                                       sizeof(KeyValuePair[A, B]) * initialSize))
-  initLock result.lock
+  initLock t.lock
 
 proc deinitSharedTable*[A, B](t: var SharedTable[A, B]) =
   deallocShared(t.data)
   deinitLock t.lock
+
+proc initSharedTable*[A, B](initialSize=64): SharedTable[A, B] {.deprecated.} =
+  ## Deprecated. Use `init` instead.
+  ## This is not posix compliant, may introduce undefined behavior.
+  assert isPowerOfTwo(initialSize)
+  result.counter = 0
+  result.dataLen = initialSize
+  result.data = cast[KeyValuePairSeq[A, B]](allocShared0(
+                                     sizeof(KeyValuePair[A, B]) * initialSize))
+  initLock result.lock
diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim
index 9b2d25267..5c73381ff 100644
--- a/lib/pure/memfiles.nim
+++ b/lib/pure/memfiles.nim
@@ -257,10 +257,13 @@ proc close*(f: var MemFile) =
   when defined(windows):
     if f.wasOpened:
       error = unmapViewOfFile(f.mem) == 0
-      lastErr = osLastError()
-      error = (closeHandle(f.mapHandle) == 0) or error
-      if f.fHandle != INVALID_HANDLE_VALUE:
-        error = (closeHandle(f.fHandle) == 0) or error
+      if not error:
+        error = closeHandle(f.mapHandle) == 0
+        if not error and f.fHandle != INVALID_HANDLE_VALUE:
+          discard closeHandle(f.fHandle)
+          f.fHandle = INVALID_HANDLE_VALUE
+      if error:
+        lastErr = osLastError()
   else:
     error = munmap(f.mem, f.size) != 0
     lastErr = osLastError()
diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim
index 7fb24c26f..7907b4e6c 100644
--- a/lib/pure/rationals.nim
+++ b/lib/pure/rationals.nim
@@ -39,7 +39,7 @@ proc toRational*[T:SomeInteger](x: T): Rational[T] =
   result.num = x
   result.den = 1
 
-proc toRational*(x: float, n: int = high(int32)): Rational[int] =
+proc toRational*(x: float, n: int = high(int) shr (sizeof(int) div 2 * 8)): Rational[int] =
   ## Calculates the best rational numerator and denominator
   ## that approximates to `x`, where the denominator is
   ## smaller than `n` (default is the largest possible
@@ -323,8 +323,13 @@ when isMainModule:
   assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7
   assert toInt(z) == 0
 
-  assert toRational(0.98765432) == 2111111029 // 2137499919
-  assert toRational(PI) == 817696623 // 260280919
+  when sizeof(int) == 8:
+    assert toRational(0.98765432) == 2111111029 // 2137499919
+    assert toRational(PI) == 817696623 // 260280919
+  when sizeof(int) == 4:
+    assert toRational(0.98765432) == 80 // 81
+    assert toRational(PI) == 355 // 113
+
   assert toRational(0.1) == 1 // 10
   assert toRational(0.9) == 9 // 10
 
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 606acbc1c..42e89e7ce 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -176,7 +176,7 @@ proc assertValidDate(monthday: MonthdayRange, month: Month, year: int) {.inline.
   assert monthday <= getDaysInMonth(month, year),
     $year & "-" & $ord(month) & "-" & $monthday & " is not a valid date"
 
-proc toEpochDay*(monthday: MonthdayRange, month: Month, year: int): int64 =
+proc toEpochDay(monthday: MonthdayRange, month: Month, year: int): int64 =
   ## Get the epoch day from a year/month/day date.
   ## The epoch day is the number of days since 1970/01/01 (it might be negative).
   assertValidDate monthday, month, year
@@ -191,7 +191,7 @@ proc toEpochDay*(monthday: MonthdayRange, month: Month, year: int): int64 =
   let doe = yoe * 365 + yoe div 4 - yoe div 100 + doy
   return era * 146097 + doe - 719468
 
-proc fromEpochDay*(epochday: int64): tuple[monthday: MonthdayRange, month: Month, year: int] =
+proc fromEpochDay(epochday: int64): tuple[monthday: MonthdayRange, month: Month, year: int] =
   ## Get the year/month/day date from a epoch day.
   ## The epoch day is the number of days since 1970/01/01 (it might be negative).
   # Based on http://howardhinnant.github.io/date_algorithms.html
@@ -1352,29 +1352,42 @@ else:
 proc fromSeconds*(since1970: float): Time {.tags: [], raises: [], benign, deprecated.} =
   ## Takes a float which contains the number of seconds since the unix epoch and
   ## returns a time object.
+  ##
+  ## **Deprecated since v0.18.0:** use ``fromUnix`` instead
   Time(since1970)
 
 proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], benign, deprecated.} =
   ## Takes an int which contains the number of seconds since the unix epoch and
   ## returns a time object.
+  ##
+  ## **Deprecated since v0.18.0:** use ``fromUnix`` instead
   Time(since1970)
 
 proc toSeconds*(time: Time): float {.tags: [], raises: [], benign, deprecated.} =
   ## Returns the time in seconds since the unix epoch.
+  ##
+  ## **Deprecated since v0.18.0:** use ``toUnix`` instead
   float(time)
 
 proc getLocalTime*(time: Time): DateTime {.tags: [], raises: [], benign, deprecated.} =
   ## Converts the calendar time `time` to broken-time representation,
   ## expressed relative to the user's specified time zone.
+  ##
+  ## **Deprecated since v0.18.0:** use ``local`` instead
   time.local
 
 proc getGMTime*(time: Time): DateTime {.tags: [], raises: [], benign, deprecated.} =
   ## Converts the calendar time `time` to broken-down time representation,
-  ## expressed in Coordinated Universal Time (UTC).
+  ## expressed in Coordinated Universal Time (UTC). 
+  ##
+  ## **Deprecated since v0.18.0:** use ``utc`` instead
   time.utc
 
 proc getTimezone*(): int {.tags: [TimeEffect], raises: [], benign, deprecated.} =
   ## Returns the offset of the local (non-DST) timezone in seconds west of UTC.
+  ##
+  ## **Deprecated since v0.18.0:** use ``now().utcOffset`` to get the current
+  ## utc offset (including DST).
   when defined(JS):
     return newDate().getTimezoneOffset() * 60
   elif defined(freebsd) or defined(netbsd) or defined(openbsd):
@@ -1468,4 +1481,4 @@ proc getDayOfWeekJulian*(day, month, year: int): WeekDay {.deprecated.} =
     y = year - a
     m = month + (12*a) - 2
     d = (5 + day + y + (y div 4) + (31*m) div 12) mod 7
-  result = d.WeekDay
\ No newline at end of file
+  result = d.WeekDay
diff --git a/lib/system.nim b/lib/system.nim
index 85643891b..4d8610737 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -743,6 +743,18 @@ proc newSeqOfCap*[T](cap: Natural): seq[T] {.
   ## ``cap``.
   discard
 
+when not defined(JS):
+  proc newSeqUninitialized*[T: SomeNumber](len: Natural): seq[T] =
+    ## creates a new sequence of type ``seq[T]`` with length ``len``.
+    ##
+    ## Only available for numbers types. Note that the sequence will be
+    ## uninitialized. After the creation of the sequence you should assign
+    ## entries to the sequence instead of adding them.
+
+    result = newSeqOfCap[T](len)
+    var s = cast[PGenericSeq](result)
+    s.len = len
+
 proc len*[TOpenArray: openArray|varargs](x: TOpenArray): int {.
   magic: "LengthOpenArray", noSideEffect.}
 proc len*(x: string): int {.magic: "LengthStr", noSideEffect.}
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index 68bf5f6c2..dac06119d 100644
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -318,7 +318,7 @@ proc initGC() =
       init(gch.marked)
       init(gch.additionalRoots)
     when hasThreadSupport:
-      gch.toDispose = initSharedList[pointer]()
+      init(gch.toDispose)
 
 when useMarkForDebug or useBackupGc:
   type
diff --git a/lib/system/gc2.nim b/lib/system/gc2.nim
index 4ecf3b226..d57a01dc7 100644
--- a/lib/system/gc2.nim
+++ b/lib/system/gc2.nim
@@ -133,7 +133,7 @@ proc initGC() =
     init(gch.additionalRoots)
     init(gch.greyStack)
     when hasThreadSupport:
-      gch.toDispose = initSharedList[pointer]()
+      init(gch.toDispose)
 
 # Which color to use for new objects is tricky: When we're marking,
 # they have to be *white* so that everything is marked that is only
diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim
index 272047bb7..5fc48d848 100644
--- a/lib/system/gc_ms.nim
+++ b/lib/system/gc_ms.nim
@@ -233,7 +233,7 @@ proc initGC() =
       init(gch.allocated)
       init(gch.marked)
     when hasThreadSupport:
-      gch.toDispose = initSharedList[pointer]()
+      init(gch.toDispose)
 
 proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} =
   var d = cast[ByteAddress](dest)
diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim
index 2b8af5bd9..7fe4c79b1 100644
--- a/tests/collections/ttables.nim
+++ b/tests/collections/ttables.nim
@@ -213,7 +213,8 @@ block clearCountTableTest:
   assert t.len() == 0
 
 block withKeyTest:
-  var t = initSharedTable[int, int]()
+  var t: SharedTable[int, int]
+  t.init()
   t.withKey(1) do (k: int, v: var int, pairExists: var bool):
     assert(v == 0)
     pairExists = true
diff --git a/tests/stdlib/tmemfiles2.nim b/tests/stdlib/tmemfiles2.nim
index 665e92e8a..7ea94cffc 100644
--- a/tests/stdlib/tmemfiles2.nim
+++ b/tests/stdlib/tmemfiles2.nim
@@ -1,10 +1,8 @@
 discard """
   file: "tmemfiles2.nim"
-  disabled: true
   output: '''Full read size: 20
 Half read size: 10 Data: Hello'''
 """
-# doesn't work on windows. fmReadWrite doesn't create a file.
 import memfiles, os
 var
   mm, mm_full, mm_half: MemFile
diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim
index 69b640fa2..870f9f865 100644
--- a/tests/testament/tester.nim
+++ b/tests/testament/tester.nim
@@ -290,20 +290,6 @@ proc compilerOutputTests(test: TTest, target: TTarget, given: var TSpec,
   if given.err == reSuccess: inc(r.passed)
   r.addResult(test, target, expectedmsg, givenmsg, given.err)
 
-proc analyzeAndConsolidateOutput(s: string): string =
-  result = ""
-  let rows = s.splitLines
-  for i in 0 ..< rows.len:
-    if (let pos = find(rows[i], "Traceback (most recent call last)"); pos != -1):
-      result = substr(rows[i], pos) & "\n"
-      for i in i+1 ..< rows.len:
-        result.add rows[i] & "\n"
-        if not (rows[i] =~ peg"['(']+ '(' \d+ ')' \s+"):
-          return
-    elif (let pos = find(rows[i], "SIGSEGV: Illegal storage access."); pos != -1):
-      result = substr(rows[i], pos)
-      return
-
 proc testSpec(r: var TResults, test: TTest, target = targetC) =
   let tname = test.name.addFileExt(".nim")
   #echo "TESTING ", tname
@@ -376,8 +362,7 @@ proc testSpec(r: var TResults, test: TTest, target = targetC) =
       if exitCode != expected.exitCode:
         r.addResult(test, target, "exitcode: " & $expected.exitCode,
                           "exitcode: " & $exitCode & "\n\nOutput:\n" &
-                          analyzeAndConsolidateOutput(bufB),
-                          reExitCodesDiffer)
+                          bufB, reExitCodesDiffer)
         continue
 
       if bufB != expectedOut and expected.action != actionRunNoSpec:
diff --git a/tests/vm/tcastint.nim b/tests/vm/tcastint.nim
new file mode 100644
index 000000000..7b9ddd7d9
--- /dev/null
+++ b/tests/vm/tcastint.nim
@@ -0,0 +1,120 @@
+discard """
+  file: "tcastint.nim"
+  output: "OK"
+"""
+
+type
+  Dollar = distinct int
+  XCoord = distinct int32
+  Digit = range[-9..0]
+
+# those are necessary for comparisons below.
+proc `==`(x, y: Dollar): bool {.borrow.}
+proc `==`(x, y: XCoord): bool {.borrow.}
+
+proc dummy[T](x: T): T = x
+
+proc test() =
+  let U8 = 0b1011_0010'u8
+  let I8 = 0b1011_0010'i8
+  let C8 = 0b1011_0010'u8.char
+  let C8_1 = 0b1011_0011'u8.char
+  let U16 = 0b10100111_00101000'u16
+  let I16 = 0b10100111_00101000'i16
+  let U32 = 0b11010101_10011100_11011010_01010000'u32
+  let I32 = 0b11010101_10011100_11011010_01010000'i32
+  let U64A = 0b11000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'u64
+  let I64A = 0b11000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'i64
+  let U64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'u64
+  let I64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'i64
+  when sizeof(int) == 8:
+    let UX = U64A.uint
+    let IX = I64A.int
+  elif sizeof(int) == 4:
+    let UX = U32.uint
+    let IX = I32.int
+  elif sizeof(int) == 2:
+    let UX = U16.uint
+    let IX = I16.int
+  else:
+    let UX = U8.uint
+    let IX = I8.int
+
+  doAssert(cast[char](I8) == C8)
+  doAssert(cast[uint8](I8) == U8)
+  doAssert(cast[uint16](I16) == U16)
+  doAssert(cast[uint32](I32) == U32)
+  doAssert(cast[uint64](I64A) == U64A)
+  doAssert(cast[uint64](I64B) == U64B)
+  doAssert(cast[int8](U8) == I8)
+  doAssert(cast[int16](U16) == I16)
+  doAssert(cast[int32](U32) == I32)
+  doAssert(cast[int64](U64A) == I64A)
+  doAssert(cast[int64](U64B) == I64B)
+  doAssert(cast[uint](IX) == UX)
+  doAssert(cast[int](UX) == IX)
+
+  doAssert(cast[char](I8 + 1) == C8_1)
+  doAssert(cast[uint8](I8 + 1) == U8 + 1)
+  doAssert(cast[uint16](I16 + 1) == U16 + 1)
+  doAssert(cast[uint32](I32 + 1) == U32 + 1)
+  doAssert(cast[uint64](I64A + 1) == U64A + 1)
+  doAssert(cast[uint64](I64B + 1) == U64B + 1)
+  doAssert(cast[int8](U8 + 1) == I8 + 1)
+  doAssert(cast[int16](U16 + 1) == I16 + 1)
+  doAssert(cast[int32](U32 + 1) == I32 + 1)
+  doAssert(cast[int64](U64A + 1) == I64A + 1)
+  doAssert(cast[int64](U64B + 1) == I64B + 1)
+  doAssert(cast[uint](IX + 1) == UX + 1)
+  doAssert(cast[int](UX + 1) == IX + 1)
+
+  doAssert(cast[char](I8.dummy) == C8.dummy)
+  doAssert(cast[uint8](I8.dummy) == U8.dummy)
+  doAssert(cast[uint16](I16.dummy) == U16.dummy)
+  doAssert(cast[uint32](I32.dummy) == U32.dummy)
+  doAssert(cast[uint64](I64A.dummy) == U64A.dummy)
+  doAssert(cast[uint64](I64B.dummy) == U64B.dummy)
+  doAssert(cast[int8](U8.dummy) == I8.dummy)
+  doAssert(cast[int16](U16.dummy) == I16.dummy)
+  doAssert(cast[int32](U32.dummy) == I32.dummy)
+  doAssert(cast[int64](U64A.dummy) == I64A.dummy)
+  doAssert(cast[int64](U64B.dummy) == I64B.dummy)
+  doAssert(cast[uint](IX.dummy) == UX.dummy)
+  doAssert(cast[int](UX.dummy) == IX.dummy)
+
+
+  doAssert(cast[int64](if false: U64B else: 0'u64) == (if false: I64B else: 0'i64))
+
+  block:
+    let raw = 3
+    let money = Dollar(raw) # this must be a variable, is otherwise constant folded.
+    doAssert(cast[int](money) == raw)
+    doAssert(cast[Dollar](raw) == money)
+  block:
+    let raw = 150'i32
+    let position = XCoord(raw) # this must be a variable, is otherwise constant folded.
+    doAssert(cast[int32](position) == raw)
+    doAssert(cast[XCoord](raw) == position)
+  block:
+    let raw = -2
+    let digit = Digit(raw)
+    doAssert(cast[int](digit) == raw)
+    doAssert(cast[Digit](raw) == digit)
+
+  when defined nimvm:
+    doAssert(not compiles(cast[float](I64A)))
+    doAssert(not compiles(cast[float32](I64A)))
+
+    doAssert(not compiles(cast[char](I64A)))
+    doAssert(not compiles(cast[uint16](I64A)))
+    doAssert(not compiles(cast[uint32](I64A)))
+
+    doAssert(not compiles(cast[uint16](I8)))
+    doAssert(not compiles(cast[uint32](I8)))
+    doAssert(not compiles(cast[uint64](I8)))
+
+test()
+static:
+  test()
+
+echo "OK"
diff --git a/tools/nimgrep.nim b/tools/nimgrep.nim
index 8dff722ec..e9c1b26fa 100644
--- a/tools/nimgrep.nim
+++ b/tools/nimgrep.nim
@@ -45,6 +45,9 @@ type
   TOptions = set[TOption]
   TConfirmEnum = enum
     ceAbort, ceYes, ceAll, ceNo, ceNone
+  Pattern = Regex | Peg
+
+using pattern: Pattern
 
 var
   filenames: seq[string] = @[]
@@ -118,7 +121,7 @@ proc highlight(s, match, repl: string, t: tuple[first, last: int],
     stdout.write("\n")
     stdout.flushFile()
 
-proc processFile(filename: string) =
+proc processFile(pattern; filename: string) =
   var filenameShown = false
   template beforeHighlight =
     if not filenameShown and optVerbose notin options:
@@ -135,18 +138,8 @@ proc processFile(filename: string) =
   if optVerbose in options:
     stdout.writeLine(filename)
     stdout.flushFile()
-  var pegp: Peg
-  var rep: Regex
   var result: string
 
-  if optRegex in options:
-    if {optIgnoreCase, optIgnoreStyle} * options != {}:
-      rep = re(pattern, {reExtended, reIgnoreCase})
-    else:
-      rep = re(pattern)
-  else:
-    pegp = peg(pattern)
-
   if optReplace in options:
     result = newStringOfCap(buffer.len)
 
@@ -156,11 +149,7 @@ proc processFile(filename: string) =
   for j in 0..high(matches): matches[j] = ""
   var reallyReplace = true
   while i < buffer.len:
-    var t: tuple[first, last: int]
-    if optRegex notin options:
-      t = findBounds(buffer, pegp, matches, i)
-    else:
-      t = findBounds(buffer, rep, matches, i)
+    let t = findBounds(buffer, pattern, matches, i)
     if t.first < 0: break
     inc(line, countLines(buffer, i, t.first-1))
 
@@ -170,11 +159,7 @@ proc processFile(filename: string) =
     if optReplace notin options:
       highlight(buffer, wholeMatch, "", t, line, showRepl=false)
     else:
-      var r: string
-      if optRegex notin options:
-        r = replace(wholeMatch, pegp, replacement % matches)
-      else:
-        r = replace(wholeMatch, rep, replacement % matches)
+      let r = replace(wholeMatch, pattern, replacement % matches)
       if optConfirm in options:
         highlight(buffer, wholeMatch, r, t, line, showRepl=true)
         case confirm()
@@ -246,17 +231,17 @@ proc styleInsensitive(s: string): string =
         addx()
     else: addx()
 
-proc walker(dir: string) =
+proc walker(pattern; dir: string) =
   for kind, path in walkDir(dir):
     case kind
     of pcFile:
       if extensions.len == 0 or path.hasRightExt(extensions):
-        processFile(path)
+        processFile(pattern, path)
     of pcDir:
       if optRecursive in options:
-        walker(path)
+        walker(pattern, path)
     else: discard
-  if existsFile(dir): processFile(dir)
+  if existsFile(dir): processFile(pattern, dir)
 
 proc writeHelp() =
   stdout.write(Usage)
@@ -332,11 +317,18 @@ else:
       pattern = "\\y " & pattern
     elif optIgnoreCase in options:
       pattern = "\\i " & pattern
+    let pegp = peg(pattern)
+    for f in items(filenames):
+      walker(pegp, f)
   else:
+    var reflags = {reStudy, reExtended}
     if optIgnoreStyle in options:
       pattern = styleInsensitive(pattern)
     if optWord in options:
       pattern = r"\b (:?" & pattern & r") \b"
-  for f in items(filenames):
-    walker(f)
+    if {optIgnoreCase, optIgnoreStyle} * options != {}:
+      reflags.incl reIgnoreCase
+    let rep = re(pattern, reflags)
+    for f in items(filenames):
+      walker(rep, f)
 
diff --git a/web/website.ini b/web/website.ini
index 32b1936d5..273c3223d 100644
--- a/web/website.ini
+++ b/web/website.ini
@@ -51,6 +51,7 @@ srcdoc2: "pure/ropes;pure/unidecode/unidecode;pure/xmldom;pure/xmldomparser"
 srcdoc2: "pure/xmlparser;pure/htmlparser;pure/xmltree;pure/colors;pure/mimetypes"
 srcdoc2: "pure/json;pure/base64;pure/scgi"
 srcdoc2: "pure/collections/tables;pure/collections/sets;pure/collections/lists"
+srcdoc2: "pure/collections/sharedlist;pure/collections/sharedtables"
 srcdoc2: "pure/collections/intsets;pure/collections/queues;pure/collections/deques;pure/encodings"
 srcdoc2: "pure/events;pure/collections/sequtils;pure/cookies"
 srcdoc2: "pure/memfiles;pure/subexes;pure/collections/critbits"