summary refs log tree commit diff stats
path: root/lib/std
diff options
context:
space:
mode:
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/appdirs.nim19
-rw-r--r--lib/std/assertions.nim20
-rw-r--r--lib/std/cmdline.nim28
-rw-r--r--lib/std/decls.nim2
-rw-r--r--lib/std/dirs.nim4
-rw-r--r--lib/std/editdistance.nim4
-rw-r--r--lib/std/effecttraits.nim2
-rw-r--r--lib/std/enumerate.nim4
-rw-r--r--lib/std/enumutils.nim40
-rw-r--r--lib/std/envvars.nim45
-rw-r--r--lib/std/exitprocs.nim34
-rw-r--r--lib/std/files.nim7
-rw-r--r--lib/std/formatfloat.nim43
-rw-r--r--lib/std/genasts.nim4
-rw-r--r--lib/std/isolation.nim6
-rw-r--r--lib/std/jsbigints.nim14
-rw-r--r--lib/std/jsonutils.nim65
-rw-r--r--lib/std/monotimes.nim4
-rw-r--r--lib/std/oserrors.nim17
-rw-r--r--lib/std/outparams.nim2
-rw-r--r--lib/std/packedsets.nim33
-rw-r--r--lib/std/paths.nim15
-rw-r--r--lib/std/private/dbutils.nim15
-rw-r--r--lib/std/private/digitsutils.nim11
-rw-r--r--lib/std/private/dragonbox.nim14
-rw-r--r--lib/std/private/gitutils.nim13
-rw-r--r--lib/std/private/globs.nim8
-rw-r--r--lib/std/private/jsutils.nim23
-rw-r--r--lib/std/private/miscdollars.nim16
-rw-r--r--lib/std/private/osappdirs.nim29
-rw-r--r--lib/std/private/oscommon.nim79
-rw-r--r--lib/std/private/osdirs.nim44
-rw-r--r--lib/std/private/osfiles.nim95
-rw-r--r--lib/std/private/ospaths2.nim82
-rw-r--r--lib/std/private/osseps.nim2
-rw-r--r--lib/std/private/ossymlinks.nim37
-rw-r--r--lib/std/private/schubfach.nim12
-rw-r--r--lib/std/private/since.nim10
-rw-r--r--lib/std/private/strimpl.nim4
-rw-r--r--lib/std/private/syslocks.nim28
-rw-r--r--lib/std/private/underscored_calls.nim22
-rw-r--r--lib/std/private/win_setenv.nim26
-rw-r--r--lib/std/setutils.nim2
-rw-r--r--lib/std/sha1.nim9
-rw-r--r--lib/std/socketstreams.nim63
-rw-r--r--lib/std/staticos.nim13
-rw-r--r--lib/std/strbasics.nim4
-rw-r--r--lib/std/symlinks.nim7
-rw-r--r--lib/std/syncio.nim51
-rw-r--r--lib/std/sysatomics.nim6
-rw-r--r--lib/std/sysrand.nim13
-rw-r--r--lib/std/tasks.nim111
-rw-r--r--lib/std/tempfiles.nim6
-rw-r--r--lib/std/time_t.nim4
-rw-r--r--lib/std/typedthreads.nim105
-rw-r--r--lib/std/varints.nim12
-rw-r--r--lib/std/widestrs.nim22
-rw-r--r--lib/std/with.nim11
-rw-r--r--lib/std/wordwrap.nim2
-rw-r--r--lib/std/wrapnils.nim4
60 files changed, 777 insertions, 650 deletions
diff --git a/lib/std/appdirs.nim b/lib/std/appdirs.nim
index e648fe0c1..963451efe 100644
--- a/lib/std/appdirs.nim
+++ b/lib/std/appdirs.nim
@@ -1,5 +1,7 @@
 ## This module implements helpers for determining special directories used by apps.
 
+## .. importdoc:: paths.nim
+
 from std/private/osappdirs import nil
 import std/paths
 import std/envvars
@@ -15,6 +17,23 @@ proc getHomeDir*(): Path {.inline, tags: [ReadEnvEffect, ReadIOEffect].} =
   ## * `getTempDir proc`_
   result = Path(osappdirs.getHomeDir())
 
+proc getDataDir*(): Path {.inline, tags: [ReadEnvEffect, ReadIOEffect].} =
+  ## Returns the data directory of the current user for applications.
+  ## 
+  ## On non-Windows OSs, this proc conforms to the XDG Base Directory
+  ## spec. Thus, this proc returns the value of the `XDG_DATA_HOME` environment
+  ## variable if it is set, otherwise it returns the default configuration
+  ## directory ("~/.local/share" or "~/Library/Application Support" on macOS).
+  ## 
+  ## See also:
+  ## * `getHomeDir proc`_
+  ## * `getConfigDir proc`_
+  ## * `getTempDir proc`_
+  ## * `expandTilde proc`_
+  ## * `getCurrentDir proc`_
+  ## * `setCurrentDir proc`_
+  result = Path(osappdirs.getDataDir())
+
 proc getConfigDir*(): Path {.inline, tags: [ReadEnvEffect, ReadIOEffect].} =
   ## Returns the config directory of the current user for applications.
   ##
diff --git a/lib/std/assertions.nim b/lib/std/assertions.nim
index 03bab1b1b..56c37d205 100644
--- a/lib/std/assertions.nim
+++ b/lib/std/assertions.nim
@@ -7,6 +7,10 @@
 #    distribution, for details about the copyright.
 #
 
+when not defined(nimPreviewSlimSystem) and not declared(sysFatal):
+  include "system/rawquits"
+  include "system/fatal"
+
 ## This module implements assertion handling.
 
 import std/private/miscdollars
@@ -23,22 +27,18 @@ proc `$`(info: InstantiationInfo): string =
 
 # ---------------------------------------------------------------------------
 
-when not defined(nimHasSinkInference):
-  {.pragma: nosinks.}
 
 proc raiseAssert*(msg: string) {.noinline, noreturn, nosinks.} =
   ## Raises an `AssertionDefect` with `msg`.
-  raise newException(AssertionDefect, msg)
+  when defined(nimPreviewSlimSystem):
+    raise newException(AssertionDefect, msg)
+  else:
+    sysFatal(AssertionDefect, msg)
 
 proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
   ## Raises an `AssertionDefect` with `msg`, but this is hidden
   ## from the effect system. Called when an assertion failed.
-  # trick the compiler to not list `AssertionDefect` when called
-  # by `assert`.
-  # xxx simplify this pending bootstrap >= 1.4.0, after which cast not needed
-  # anymore since `Defect` can't be raised.
-  type Hide = proc (msg: string) {.noinline, raises: [], noSideEffect, tags: [].}
-  cast[Hide](raiseAssert)(msg)
+  raiseAssert(msg)
 
 template assertImpl(cond: bool, msg: string, expr: string, enabled: static[bool]) =
   when enabled:
@@ -98,6 +98,7 @@ template doAssertRaises*(exception: typedesc, code: untyped) =
   const begin = "expected raising '" & astToStr(exception) & "', instead"
   const msgEnd = " by: " & astToStr(code)
   template raisedForeign {.gensym.} = raiseAssert(begin & " raised foreign exception" & msgEnd)
+  {.push warning[BareExcept]:off.}
   when Exception is exception:
     try:
       if true:
@@ -116,5 +117,6 @@ template doAssertRaises*(exception: typedesc, code: untyped) =
       mixin `$` # alternatively, we could define $cstring in this module
       raiseAssert(begin & " raised '" & $e.name & "'" & msgEnd)
     except: raisedForeign()
+  {.pop.}
   if wrong:
     raiseAssert(begin & " nothing was raised" & msgEnd)
diff --git a/lib/std/cmdline.nim b/lib/std/cmdline.nim
index 3208da1b8..0ba4619e5 100644
--- a/lib/std/cmdline.nim
+++ b/lib/std/cmdline.nim
@@ -30,9 +30,9 @@ const weirdTarget = defined(nimscript) or defined(js)
 when weirdTarget:

   discard

 elif defined(windows):

-  import winlean

+  import std/winlean

 elif defined(posix):

-  import posix

+  import std/posix

 else:

   {.error: "The cmdline module has not been implemented for the target platform.".}

 

@@ -40,10 +40,7 @@ else:
 # Needed by windows in order to obtain the command line for targets

 # other than command line targets

 when defined(windows) and not weirdTarget:

-  when useWinUnicode:

-    template getCommandLine*(): untyped = getCommandLineW()

-  else:

-    template getCommandLine*(): untyped = getCommandLineA()

+  template getCommandLine*(): untyped = getCommandLineW()

 

 

 proc parseCmdLine*(c: string): seq[string] {.

@@ -141,7 +138,7 @@ proc parseCmdLine*(c: string): seq[string] {.
         while i < c.len and c[i] > ' ':

           add(a, c[i])

           inc(i)

-    add(result, a)

+    add(result, move a)

 

 when defined(nimdoc):

   # Common forward declaration docstring block for parameter retrieval procs.

@@ -166,11 +163,12 @@ when defined(nimdoc):
     ##

     ## **Examples:**

     ##

-    ## .. code-block:: nim

+    ##   ```nim

     ##   when declared(paramCount):

     ##     # Use paramCount() here

     ##   else:

     ##     # Do something else!

+    ##   ```

 

   proc paramStr*(i: int): string {.tags: [ReadIOEffect].} =

     ## Returns the `i`-th `command line argument`:idx: given to the application.

@@ -183,7 +181,7 @@ when defined(nimdoc):
     ## Similarly to `argv`:idx: in C,

     ## it is possible to call `paramStr(0)` but this will return OS specific

     ## contents (usually the name of the invoked executable). You should avoid

-    ## this and call `getAppFilename()`_ instead.

+    ## this and call `getAppFilename() <os.html#getAppFilename>`_ instead.

     ##

     ## **Availability**: When generating a dynamic library (see `--app:lib`) on

     ## Posix this proc is not defined.

@@ -194,15 +192,16 @@ when defined(nimdoc):
     ## * `parseCmdLine proc`_

     ## * `paramCount proc`_

     ## * `commandLineParams proc`_

-    ## * `getAppFilename proc`_

+    ## * `getAppFilename proc <os.html#getAppFilename>`_

     ##

     ## **Examples:**

     ##

-    ## .. code-block:: nim

+    ##   ```nim

     ##   when declared(paramStr):

     ##     # Use paramStr() here

     ##   else:

     ##     # Do something else!

+    ##   ```

 

 elif defined(nimscript): discard

 elif defined(nodejs):

@@ -283,7 +282,7 @@ when declared(paramCount) or defined(nimdoc):
     ## Convenience proc which returns the command line parameters.

     ##

     ## This returns **only** the parameters. If you want to get the application

-    ## executable filename, call `getAppFilename()`_.

+    ## executable filename, call `getAppFilename() <os.html#getAppFilename>`_.

     ##

     ## **Availability**: On Posix there is no portable way to get the command

     ## line from a DLL and thus the proc isn't defined in this environment. You

@@ -295,15 +294,16 @@ when declared(paramCount) or defined(nimdoc):
     ## * `parseCmdLine proc`_

     ## * `paramCount proc`_

     ## * `paramStr proc`_

-    ## * `getAppFilename proc`_

+    ## * `getAppFilename proc <os.html#getAppFilename>`_

     ##

     ## **Examples:**

     ##

-    ## .. code-block:: nim

+    ##   ```nim

     ##   when declared(commandLineParams):

     ##     # Use commandLineParams() here

     ##   else:

     ##     # Do something else!

+    ##   ```

     result = @[]

     for i in 1..paramCount():

       result.add(paramStr(i))

diff --git a/lib/std/decls.nim b/lib/std/decls.nim
index 3f774cd08..bb7ec3593 100644
--- a/lib/std/decls.nim
+++ b/lib/std/decls.nim
@@ -1,6 +1,6 @@
 ## This module implements syntax sugar for some declarations.
 
-import macros
+import std/macros
 
 macro byaddr*(sect) =
   ## Allows a syntax for l-value references, being an exact analog to
diff --git a/lib/std/dirs.nim b/lib/std/dirs.nim
index df6107c51..380d6d08f 100644
--- a/lib/std/dirs.nim
+++ b/lib/std/dirs.nim
@@ -1,6 +1,6 @@
 ## This module implements directory handling.
 
-from paths import Path, ReadDirEffect, WriteDirEffect
+from std/paths import Path, ReadDirEffect, WriteDirEffect
 
 from std/private/osdirs import dirExists, createDir, existsOrCreateDir, removeDir,
                                moveDir, walkDir, setCurrentDir,
@@ -8,7 +8,7 @@ from std/private/osdirs import dirExists, createDir, existsOrCreateDir, removeDi
 
 export PathComponent
 
-proc dirExists*(dir: Path): bool {.inline, tags: [ReadDirEffect].} =
+proc dirExists*(dir: Path): bool {.inline, tags: [ReadDirEffect], sideEffect.} =
   ## Returns true if the directory `dir` exists. If `dir` is a file, false
   ## is returned. Follows symlinks.
   result = dirExists(dir.string)
diff --git a/lib/std/editdistance.nim b/lib/std/editdistance.nim
index 9f29c5c05..40c0017ae 100644
--- a/lib/std/editdistance.nim
+++ b/lib/std/editdistance.nim
@@ -10,7 +10,7 @@
 ## This module implements an algorithm to compute the
 ## `edit distance`:idx: between two Unicode strings.
 
-import unicode
+import std/unicode
 
 proc editDistance*(a, b: string): int {.noSideEffect.} =
   ## Returns the **unicode-rune** edit distance between `a` and `b`.
@@ -18,7 +18,7 @@ proc editDistance*(a, b: string): int {.noSideEffect.} =
   ## This uses the `Levenshtein`:idx: distance algorithm with only a linear
   ## memory overhead.
   runnableExamples: static: doAssert editdistance("Kitten", "Bitten") == 1
-  if len(a) > len(b):
+  if runeLen(a) > runeLen(b):
     # make `b` the longer string
     return editDistance(b, a)
   # strip common prefix
diff --git a/lib/std/effecttraits.nim b/lib/std/effecttraits.nim
index fb057a669..3d1b4ffd3 100644
--- a/lib/std/effecttraits.nim
+++ b/lib/std/effecttraits.nim
@@ -14,7 +14,7 @@
 ## One can test for the existence of this standard module
 ## via `defined(nimHasEffectTraitsModule)`.
 
-import macros
+import std/macros
 
 proc getRaisesListImpl(n: NimNode): NimNode = discard "see compiler/vmops.nim"
 proc getTagsListImpl(n: NimNode): NimNode = discard "see compiler/vmops.nim"
diff --git a/lib/std/enumerate.nim b/lib/std/enumerate.nim
index a8f0e1ba7..beb65ed30 100644
--- a/lib/std/enumerate.nim
+++ b/lib/std/enumerate.nim
@@ -11,7 +11,7 @@
 ## macro system.
 
 import std/private/since
-import macros
+import std/macros
 
 
 macro enumerate*(x: ForLoopStmt): untyped {.since: (1, 3).} =
@@ -21,7 +21,7 @@ macro enumerate*(x: ForLoopStmt): untyped {.since: (1, 3).} =
   ## The default starting count `0` can be manually overridden if needed.
   runnableExamples:
     let a = [10, 20, 30]
-    var b: seq[(int, int)]
+    var b: seq[(int, int)] = @[]
     for i, x in enumerate(a):
       b.add((i, x))
     assert b == @[(0, 10), (1, 20), (2, 30)]
diff --git a/lib/std/enumutils.nim b/lib/std/enumutils.nim
index 9d4ff1bcf..9c338817d 100644
--- a/lib/std/enumutils.nim
+++ b/lib/std/enumutils.nim
@@ -7,8 +7,8 @@
 #    distribution, for details about the copyright.
 #
 
-import macros
-from typetraits import OrdinalEnum, HoleyEnum
+import std/macros
+from std/typetraits import OrdinalEnum, HoleyEnum
 
 when defined(nimPreviewSlimSystem):
   import std/assertions
@@ -21,32 +21,34 @@ macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed,
   # Generates a case stmt, which assigns the correct enum field given
   # a normalized string comparison to the `argSym` input.
   # string normalization is done using passed normalizer.
-  # NOTE: for an enum with fields Foo, Bar, ... we cannot generate
-  # `of "Foo".nimIdentNormalize: Foo`.
-  # This will fail, if the enum is not defined at top level (e.g. in a block).
-  # Thus we check for the field value of the (possible holed enum) and convert
-  # the integer value to the generic argument `typ`.
   let typ = typ.getTypeInst[1]
-  let impl = typ.getImpl[2]
+  let typSym = typ.getTypeImpl.getTypeInst # skip aliases etc to get type sym
+  let impl = typSym.getImpl[2]
   expectKind impl, nnkEnumTy
   let normalizerNode = quote: `normalizer`
   expectKind normalizerNode, nnkSym
   result = nnkCaseStmt.newTree(newCall(normalizerNode, argSym))
   # stores all processed field strings to give error msg for ambiguous enums
   var foundFields: seq[string] = @[]
+  var fVal = ""
   var fStr = "" # string of current field
   var fNum = BiggestInt(0) # int value of current field
   for f in impl:
     case f.kind
     of nnkEmpty: continue # skip first node of `enumTy`
-    of nnkSym, nnkIdent: fStr = f.strVal
+    of nnkSym, nnkIdent:
+      fVal = f.strVal
+      fStr = fVal
     of nnkAccQuoted:
-      fStr = ""
+      fVal = ""
       for ch in f:
-        fStr.add ch.strVal
+        fVal.add ch.strVal
+      fStr = fVal
     of nnkEnumFieldDef:
+      fVal = f[0].strVal
       case f[1].kind
-      of nnkStrLit: fStr = f[1].strVal
+      of nnkStrLit:
+        fStr = f[1].strVal
       of nnkTupleConstr:
         fStr = f[1][1].strVal
         fNum = f[1][0].intVal
@@ -64,7 +66,7 @@ macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed,
     if fNum >= userMin and fNum <= userMax:
       fStr = normalizer(fStr)
       if fStr notin foundFields:
-        result.add nnkOfBranch.newTree(newLit fStr,  nnkCall.newTree(typ, newLit fNum))
+        result.add nnkOfBranch.newTree(newLit fStr, newDotExpr(typ, ident fVal))
         foundFields.add fStr
       else:
         error("Ambiguous enums cannot be parsed, field " & $fStr &
@@ -80,7 +82,7 @@ macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed,
     result.add nnkElse.newTree(default)
 
 macro enumFullRange(a: typed): untyped =
-  newNimNode(nnkCurly).add(a.getType[1][1..^1])
+  newNimNode(nnkBracket).add(a.getType[1][1..^1])
 
 macro enumNames(a: typed): untyped =
   # this could be exported too; in particular this could be useful for enum with holes.
@@ -112,9 +114,9 @@ const invalidSlot = uint8.high
 
 proc genLookup[T: typedesc[HoleyEnum]](_: T): auto =
   const n = span(T)
-  var ret: array[n, uint8]
   var i = 0
   assert n <= invalidSlot.int
+  var ret {.noinit.}: array[n, uint8]
   for ai in mitems(ret): ai = invalidSlot
   for ai in items(T):
     ret[ai.ord - T.low.ord] = uint8(i)
@@ -172,6 +174,9 @@ template symbolRank*[T: enum](a: T): int =
   when T is Ordinal: ord(a) - T.low.ord.static
   else: symbolRankImpl(a)
 
+proc rangeBase(T: typedesc): typedesc {.magic: "TypeTrait".}
+  # skip one level of range; return the base type of a range type
+
 func symbolName*[T: enum](a: T): string =
   ## Returns the symbol name of an enum.
   ##
@@ -190,5 +195,8 @@ func symbolName*[T: enum](a: T): string =
       c1 = 4
       c2 = 20
     assert c1.symbolName == "c1"
-  const names = enumNames(T)
+  when T is range:
+    const names = enumNames(rangeBase T)
+  else:
+    const names = enumNames(T)
   names[a.symbolRank]
diff --git a/lib/std/envvars.nim b/lib/std/envvars.nim
index 46595a3cf..a955077ea 100644
--- a/lib/std/envvars.nim
+++ b/lib/std/envvars.nim
@@ -60,12 +60,16 @@ when not defined(nimscript):
     when defined(windows):
       proc c_putenv(envstring: cstring): cint {.importc: "_putenv", header: "<stdlib.h>".}
       from std/private/win_setenv import setEnvImpl
-      import winlean
+      import std/winlean
       when defined(nimPreviewSlimSystem):
         import std/widestrs
-      proc c_wgetenv(varname: WideCString): WideCString {.importc: "_wgetenv",
+
+      type wchar_t {.importc: "wchar_t", header: "<stdlib.h>".} = int16
+      proc c_wgetenv(varname: ptr wchar_t): ptr wchar_t {.importc: "_wgetenv",
           header: "<stdlib.h>".}
-      proc getEnvImpl(env: cstring): WideCString = c_wgetenv(env.newWideCString)
+      proc getEnvImpl(env: cstring): WideCString =
+        let r: WideCString = env.newWideCString
+        cast[WideCString](c_wgetenv(cast[ptr wchar_t](r)))
     else:
       proc c_getenv(env: cstring): cstring {.
         importc: "getenv", header: "<stdlib.h>".}
@@ -90,8 +94,10 @@ when not defined(nimscript):
         assert getEnv("unknownEnv", "doesn't exist") == "doesn't exist"
 
       let env = getEnvImpl(key)
-      if env == nil: return default
-      result = $env
+      if env == nil:
+        result = default
+      else:
+        result = $env
 
     proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} =
       ## Checks whether the environment variable named `key` exists.
@@ -105,7 +111,7 @@ when not defined(nimscript):
       runnableExamples:
         assert not existsEnv("unknownEnv")
 
-      return getEnvImpl(key) != nil
+      result = getEnvImpl(key) != nil
 
     proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} =
       ## Sets the value of the `environment variable`:idx: named `key` to `val`.
@@ -136,7 +142,7 @@ when not defined(nimscript):
       ## * `envPairs iterator`_
       template bail = raiseOSError(osLastError(), key)
       when defined(windows):
-        #[ 
+        #[
         # https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/putenv-s-wputenv-s?view=msvc-160
         > You can remove a variable from the environment by specifying an empty string (that is, "") for value_string
         note that nil is not legal
@@ -173,20 +179,17 @@ when not defined(nimscript):
 
     iterator envPairsImpl(): tuple[key, value: string] {.tags: [ReadEnvEffect].} =
       when defined(windows):
-        block implBlock:
-          template impl(get_fun, typ, size, zero, free_fun) =
-            let env = get_fun()
-            var e = env
-            if e == nil: break implBlock
-            while true:
-              let eend = strEnd(e)
-              let kv = $e
-              let p = find(kv, '=')
-              yield (substr(kv, 0, p-1), substr(kv, p+1))
-              e = cast[typ](cast[ByteAddress](eend)+size)
-              if typeof(zero)(eend[1]) == zero: break
-            discard free_fun(env)
-          impl(getEnvironmentStringsW, WideCString, 2, 0, freeEnvironmentStringsW)
+        let env = getEnvironmentStringsW()
+        var e = env
+        if e != nil:
+          while true:
+            let eend = strEnd(e)
+            let kv = $e
+            let p = find(kv, '=')
+            yield (substr(kv, 0, p-1), substr(kv, p+1))
+            e = cast[WideCString](cast[ByteAddress](eend)+2)
+            if int(eend[1]) == 0: break
+          discard freeEnvironmentStringsW(env)
       else:
         var i = 0
         when defined(macosx) and not defined(ios) and not defined(emscripten):
diff --git a/lib/std/exitprocs.nim b/lib/std/exitprocs.nim
index d63c1abc5..f26368f42 100644
--- a/lib/std/exitprocs.nim
+++ b/lib/std/exitprocs.nim
@@ -9,7 +9,9 @@
 
 ## This module allows adding hooks to program exit.
 
-import locks
+import std/locks
+when defined(js) and not defined(nodejs):
+  import std/assertions
 
 type
   FunKind = enum kClosure, kNoconv # extend as needed
@@ -20,20 +22,20 @@ type
 
 var
   gFunsLock: Lock
-  gFuns: seq[Fun]
+  gFuns {.cursor.}: seq[Fun] #Intentionally use the cursor to break up the lifetime trace and make it compatible with JS.
 
 initLock(gFunsLock)
 
 when defined(js):
   proc addAtExit(quitProc: proc() {.noconv.}) =
     when defined(nodejs):
-      asm """
+      {.emit: """
         process.on('exit', `quitProc`);
-      """
+      """.}
     elif defined(js):
-      asm """
+      {.emit: """
         window.onbeforeunload = `quitProc`;
-      """
+      """.}
 else:
   proc addAtExit(quitProc: proc() {.noconv.}) {.
     importc: "atexit", header: "<stdlib.h>".}
@@ -45,6 +47,7 @@ proc callClosures() {.noconv.} =
       case fun.kind
       of kClosure: fun.fun1()
       of kNoconv: fun.fun2()
+    gFuns.setLen(0)
 
 template fun() =
   if gFuns.len == 0:
@@ -66,24 +69,19 @@ proc addExitProc*(cl: proc() {.noconv.}) =
     fun()
     gFuns.add Fun(kind: kNoconv, fun2: cl)
 
-when not defined(nimscript):
+when not defined(nimscript) and (not defined(js) or defined(nodejs)):
   proc getProgramResult*(): int =
     when defined(js) and defined(nodejs):
-      asm """
+      {.emit: """
 `result` = process.exitCode;
-"""
-    elif not defined(js):
-      result = programResult
+""".}
     else:
-      doAssert false
+      result = programResult
 
   proc setProgramResult*(a: int) =
-    # pending https://github.com/nim-lang/Nim/issues/14674
     when defined(js) and defined(nodejs):
-      asm """
+      {.emit: """
 process.exitCode = `a`;
-"""
-    elif not defined(js):
-      programResult = a
+""".}
     else:
-      doAssert false
+      programResult = a
diff --git a/lib/std/files.nim b/lib/std/files.nim
index 138bb5234..c4e0491c9 100644
--- a/lib/std/files.nim
+++ b/lib/std/files.nim
@@ -1,12 +1,15 @@
 ## This module implements file handling.
+##
+## **See also:**
+## * `paths module <paths.html>`_ for path manipulation
 
-from paths import Path, ReadDirEffect, WriteDirEffect
+from std/paths import Path, ReadDirEffect, WriteDirEffect
 
 from std/private/osfiles import fileExists, removeFile,
                                 moveFile
 
 
-proc fileExists*(filename: Path): bool {.inline, tags: [ReadDirEffect].} =
+proc fileExists*(filename: Path): bool {.inline, tags: [ReadDirEffect], sideEffect.} =
   ## Returns true if `filename` exists and is a regular file or symlink.
   ##
   ## Directories, device files, named pipes and sockets return false.
diff --git a/lib/std/formatfloat.nim b/lib/std/formatfloat.nim
index 8abbe59cd..9258245f6 100644
--- a/lib/std/formatfloat.nim
+++ b/lib/std/formatfloat.nim
@@ -11,8 +11,6 @@
 
 when defined(nimPreviewSlimSystem):
   import std/assertions
-else:
-  {.deprecated: "formatfloat is about to move out of system; use `-d:nimPreviewSlimSystem` and import `std/formatfloat`".}
 
 proc c_memcpy(a, b: pointer, size: csize_t): pointer {.importc: "memcpy", header: "<string.h>", discardable.}
 
@@ -37,8 +35,8 @@ proc writeFloatToBufferRoundtrip*(buf: var array[65, char]; value: float32): int
   result = float32ToChars(buf, value, forceTrailingDotZero=true).int
   buf[result] = '\0'
 
-proc c_sprintf(buf, frmt: cstring): cint {.header: "<stdio.h>",
-                                    importc: "sprintf", varargs, noSideEffect.}
+proc c_snprintf(buf: cstring, n: csize_t, frmt: cstring): cint {.header: "<stdio.h>",
+                                    importc: "snprintf", varargs, noSideEffect.}
 
 proc writeToBuffer(buf: var array[65, char]; value: cstring) =
   var i = 0
@@ -51,7 +49,7 @@ proc writeFloatToBufferSprintf*(buf: var array[65, char]; value: BiggestFloat):
   ##
   ## returns the amount of bytes written to `buf` not counting the
   ## terminating '\0' character.
-  var n = c_sprintf(cast[cstring](addr buf), "%.16g", value).int
+  var n = c_snprintf(cast[cstring](addr buf), 65, "%.16g", value).int
   var hasDot = false
   for i in 0..n-1:
     if buf[i] == ',':
@@ -88,7 +86,7 @@ proc writeFloatToBuffer*(buf: var array[65, char]; value: BiggestFloat | float32
 
 proc addFloatRoundtrip*(result: var string; x: float | float32) =
   when nimvm:
-    doAssert false
+    raiseAssert "unreachable"
   else:
     var buffer {.noinit.}: array[65, char]
     let n = writeFloatToBufferRoundtrip(buffer, x)
@@ -96,28 +94,29 @@ proc addFloatRoundtrip*(result: var string; x: float | float32) =
 
 proc addFloatSprintf*(result: var string; x: float) =
   when nimvm:
-    doAssert false
+    raiseAssert "unreachable"
   else:
     var buffer {.noinit.}: array[65, char]
     let n = writeFloatToBufferSprintf(buffer, x)
     result.addCstringN(cast[cstring](buffer[0].addr), n)
 
-proc nimFloatToString(a: float): cstring =
-  ## ensures the result doesn't print like an integer, i.e. return 2.0, not 2
-  # print `-0.0` properly
-  asm """
-    function nimOnlyDigitsOrMinus(n) {
-      return n.toString().match(/^-?\d+$/);
-    }
-    if (Number.isSafeInteger(`a`))
-      `result` = `a` === 0 && 1 / `a` < 0 ? "-0.0" : `a`+".0"
-    else {
-      `result` = `a`+""
-      if(nimOnlyDigitsOrMinus(`result`)){
-        `result` = `a`+".0"
+when defined(js):
+  proc nimFloatToString(a: float): cstring =
+    ## ensures the result doesn't print like an integer, i.e. return 2.0, not 2
+    # print `-0.0` properly
+    {.emit: """
+      function nimOnlyDigitsOrMinus(n) {
+        return n.toString().match(/^-?\d+$/);
       }
-    }
-  """
+      if (Number.isSafeInteger(`a`))
+        `result` = `a` === 0 && 1 / `a` < 0 ? "-0.0" : `a`+".0";
+      else {
+        `result` = `a`+"";
+        if(nimOnlyDigitsOrMinus(`result`)){
+          `result` = `a`+".0";
+        }
+      }
+    """.}
 
 proc addFloat*(result: var string; x: float | float32) {.inline.} =
   ## Converts float to its string representation and appends it to `result`.
diff --git a/lib/std/genasts.nim b/lib/std/genasts.nim
index 05b2823ef..d0f07c527 100644
--- a/lib/std/genasts.nim
+++ b/lib/std/genasts.nim
@@ -1,6 +1,6 @@
 ## This module implements AST generation using captured variables for macros.
 
-import macros
+import std/macros
 
 type GenAstOpt* = enum
   kDirtyTemplate,
@@ -24,7 +24,7 @@ macro genAstOpt*(options: static set[GenAstOpt], args: varargs[untyped]): untype
       result = genAst(cond, s = repr(cond), lhs = cond[1], rhs = cond[2]):
         # each local symbol we access must be explicitly captured
         if not cond:
-          doAssert false, "'$#'' failed: lhs: '$#', rhs: '$#'" % [s, $lhs, $rhs]
+          raiseAssert "'$#'' failed: lhs: '$#', rhs: '$#'" % [s, $lhs, $rhs]
     let a = 3
     check2 a*2 == a+3
     if false: check2 a*2 < a+1 # would error with: 'a * 2 < a + 1'' failed: lhs: '6', rhs: '4'
diff --git a/lib/std/isolation.nim b/lib/std/isolation.nim
index 7d6ac6092..b03e00651 100644
--- a/lib/std/isolation.nim
+++ b/lib/std/isolation.nim
@@ -15,7 +15,7 @@
 ##
 
 type
-  Isolated*[T] = object ## Isolated data can only be moved, not copied.
+  Isolated*[T] {.sendable.} = object ## Isolated data can only be moved, not copied.
     value: T
 
 proc `=copy`*[T](dest: var Isolated[T]; src: Isolated[T]) {.error.}
@@ -38,9 +38,9 @@ func isolate*[T](value: sink T): Isolated[T] {.magic: "Isolate".} =
 
 func unsafeIsolate*[T](value: sink T): Isolated[T] =
   ## Creates an isolated subgraph from the expression `value`.
-  ## 
+  ##
   ## .. warning:: The proc doesn't check whether `value` is isolated.
-  ## 
+  ##
   Isolated[T](value: value)
 
 func extract*[T](src: var Isolated[T]): T =
diff --git a/lib/std/jsbigints.nim b/lib/std/jsbigints.nim
index 04578fc87..4e996ea7b 100644
--- a/lib/std/jsbigints.nim
+++ b/lib/std/jsbigints.nim
@@ -14,7 +14,7 @@ func big*(integer: SomeInteger): JsBigInt {.importjs: "BigInt(#)".} =
   runnableExamples:
     doAssert big(1234567890) == big"1234567890"
     doAssert 0b1111100111.big == 0o1747.big and 0o1747.big == 999.big
-  when nimvm: doAssert false, "JsBigInt can not be used at compile-time nor static context" else: discard
+  when nimvm: raiseAssert "JsBigInt can not be used at compile-time nor static context" else: discard
 
 func `'big`*(num: cstring): JsBigInt {.importjs: "BigInt(#)".} =
   ## Constructor for `JsBigInt`.
@@ -28,11 +28,11 @@ func `'big`*(num: cstring): JsBigInt {.importjs: "BigInt(#)".} =
     doAssert 0xdeadbeaf'big == 0xdeadbeaf.big
     doAssert 0xffffffffffffffff'big == (1'big shl 64'big) - 1'big
     doAssert not compiles(static(12'big))
-  when nimvm: doAssert false, "JsBigInt can not be used at compile-time nor static context" else: discard
+  when nimvm: raiseAssert "JsBigInt can not be used at compile-time nor static context" else: discard
 
 func big*(integer: cstring): JsBigInt {.importjs: "BigInt(#)".} =
   ## Alias for `'big`
-  when nimvm: doAssert false, "JsBigInt can not be used at compile-time nor static context" else: discard
+  when nimvm: raiseAssert "JsBigInt can not be used at compile-time nor static context" else: discard
 
 func toCstring*(this: JsBigInt; radix: 2..36): cstring {.importjs: "#.toString(#)".} =
   ## Converts from `JsBigInt` to `cstring` representation.
@@ -64,10 +64,10 @@ func wrapToUint*(this: JsBigInt; bits: Natural): JsBigInt {.importjs:
   runnableExamples:
     doAssert (big("3") + big("2") ** big("66")).wrapToUint(66) == big("3")
 
-func toNumber*(this: JsBigInt): BiggestInt {.importjs: "Number(#)".} =
+func toNumber*(this: JsBigInt): int {.importjs: "Number(#)".} =
   ## Does not do any bounds check and may or may not return an inexact representation.
   runnableExamples:
-    doAssert toNumber(big"2147483647") == 2147483647.BiggestInt
+    doAssert toNumber(big"2147483647") == 2147483647.int
 
 func `+`*(x, y: JsBigInt): JsBigInt {.importjs: "(# $1 #)".} =
   runnableExamples:
@@ -110,7 +110,7 @@ func `==`*(x, y: JsBigInt): bool {.importjs: "(# == #)".} =
     doAssert big"42" == big"42"
 
 func `**`*(x, y: JsBigInt): JsBigInt {.importjs: "((#) $1 #)".} =
-  # (#) needed, refs https://github.com/nim-lang/Nim/pull/16409#issuecomment-760550812
+  # (#) needed due to unary minus
   runnableExamples:
     doAssert big"2" ** big"64" == big"18446744073709551616"
     doAssert big"-2" ** big"3" == big"-8"
@@ -120,8 +120,6 @@ func `**`*(x, y: JsBigInt): JsBigInt {.importjs: "((#) $1 #)".} =
     try: discard big"2" ** big"-1" # raises foreign `RangeError`
     except: ok = true
     doAssert ok
-  # pending https://github.com/nim-lang/Nim/pull/15940, simplify to:
-  # doAssertRaises: discard big"2" ** big"-1" # raises foreign `RangeError`
 
 func `and`*(x, y: JsBigInt): JsBigInt {.importjs: "(# & #)".} =
   runnableExamples:
diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim
index eec8dea7d..2d28748ce 100644
--- a/lib/std/jsonutils.nim
+++ b/lib/std/jsonutils.nim
@@ -16,7 +16,7 @@ runnableExamples:
   assert 0.0.toJson.kind == JFloat
   assert Inf.toJson.kind == JString
 
-import json, strutils, tables, sets, strtabs, options, strformat
+import std/[json, strutils, tables, sets, strtabs, options, strformat]
 
 #[
 Future directions:
@@ -30,29 +30,15 @@ add a way to customize serialization, for e.g.:
   objects.
 ]#
 
-import macros
-from enumutils import symbolName
-from typetraits import OrdinalEnum, tupleLen
+import std/macros
+from std/enumutils import symbolName
+from std/typetraits import OrdinalEnum, tupleLen
 
 when defined(nimPreviewSlimSystem):
   import std/assertions
 
-when not defined(nimFixedForwardGeneric):
-  # xxx remove pending csources_v1 update >= 1.2.0
-  proc to[T](node: JsonNode, t: typedesc[T]): T =
-    when T is string: node.getStr
-    elif T is bool: node.getBool
-    else: static: doAssert false, $T # support as needed (only needed during bootstrap)
-  proc isNamedTuple(T: typedesc): bool = # old implementation
-    when T isnot tuple: result = false
-    else:
-      var t: T
-      for name, _ in t.fieldPairs:
-        when name == "Field0": return compiles(t.Field0)
-        else: return true
-      return false
-else:
-  proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".}
+
+proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".}
 
 type
   Joptions* = object # xxx rename FromJsonOptions
@@ -92,19 +78,24 @@ macro getDiscriminants(a: typedesc): seq[string] =
   let sym = a[1]
   let t = sym.getTypeImpl
   let t2 = t[2]
-  doAssert t2.kind == nnkRecList
-  result = newTree(nnkBracket)
-  for ti in t2:
-    if ti.kind == nnkRecCase:
-      let key = ti[0][0]
-      let typ = ti[0][1]
-      result.add newLit key.strVal
-  if result.len > 0:
+  case t2.kind
+  of nnkEmpty: # allow empty objects
     result = quote do:
-      @`result`
+        seq[string].default
+  of nnkRecList:
+    result = newTree(nnkBracket)
+    for ti in t2:
+      if ti.kind == nnkRecCase:
+        let key = ti[0][0]
+        result.add newLit key.strVal
+    if result.len > 0:
+      result = quote do:
+        @`result`
+    else:
+      result = quote do:
+        seq[string].default
   else:
-    result = quote do:
-      seq[string].default
+    raiseAssert "unexpected kind: " & $t2.kind
 
 macro initCaseObject(T: typedesc, fun: untyped): untyped =
   ## does the minimum to construct a valid case object, only initializing
@@ -118,7 +109,7 @@ macro initCaseObject(T: typedesc, fun: untyped): untyped =
   case t.kind
   of nnkObjectTy: t2 = t[2]
   of nnkRefTy: t2 = t[0].getTypeImpl[2]
-  else: doAssert false, $t.kind # xxx `nnkPtrTy` could be handled too
+  else: raiseAssert $t.kind # xxx `nnkPtrTy` could be handled too
   doAssert t2.kind == nnkRecList
   result = newTree(nnkObjConstr)
   result.add sym
@@ -231,12 +222,7 @@ proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) =
   elif T is uint|uint64: a = T(to(b, uint64))
   elif T is Ordinal: a = cast[T](to(b, int))
   elif T is pointer: a = cast[pointer](to(b, int))
-  elif T is distinct:
-    when nimvm:
-      # bug, potentially related to https://github.com/nim-lang/Nim/issues/12282
-      a = T(jsonTo(b, distinctBase(T)))
-    else:
-      a.distinctBase.fromJson(b)
+  elif T is distinct: a.distinctBase.fromJson(b)
   elif T is string|SomeNumber: a = to(b,T)
   elif T is cstring:
     case b.kind
@@ -303,7 +289,7 @@ proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) =
         i.inc
   else:
     # checkJson not appropriate here
-    static: doAssert false, "not yet implemented: " & $T
+    static: raiseAssert "not yet implemented: " & $T
 
 proc jsonTo*(b: JsonNode, T: typedesc, opt = Joptions()): T =
   ## reverse of `toJson`
@@ -385,7 +371,6 @@ proc toJsonHook*[K: string|cstring, V](t: (Table[K, V] | OrderedTable[K, V]), op
   ##
   ## See also:
   ## * `fromJsonHook proc<#fromJsonHook,,JsonNode>`_
-  # pending PR #9217 use: toSeq(a) instead of `collect` in `runnableExamples`.
   runnableExamples:
     import std/[tables, json, sugar]
     let foo = (
diff --git a/lib/std/monotimes.nim b/lib/std/monotimes.nim
index 5c67a5d4c..bf6dc776b 100644
--- a/lib/std/monotimes.nim
+++ b/lib/std/monotimes.nim
@@ -36,7 +36,7 @@ See also
 * `times module <times.html>`_
 ]##
 
-import times
+import std/times
 
 type
   MonoTime* = object ## Represents a monotonic timestamp.
@@ -74,7 +74,7 @@ when defined(js):
   {.pop.}
 
 elif defined(posix) and not defined(osx):
-  import posix
+  import std/posix
 
 when defined(zephyr):
   proc k_uptime_ticks(): int64 {.importc: "k_uptime_ticks", header: "<kernel.h>".}
diff --git a/lib/std/oserrors.nim b/lib/std/oserrors.nim
index 8d06c41da..7b11c5e8e 100644
--- a/lib/std/oserrors.nim
+++ b/lib/std/oserrors.nim
@@ -15,7 +15,7 @@ type
 
 when not defined(nimscript):
   when defined(windows):
-    import winlean
+    import std/winlean
     when defined(nimPreviewSlimSystem):
       import std/widestrs
   else:
@@ -75,17 +75,14 @@ proc newOSError*(
   ## See also:
   ## * `osErrorMsg proc`_
   ## * `osLastError proc`_
-  var e: owned(ref OSError); new(e)
-  e.errorCode = errorCode.int32
-  e.msg = osErrorMsg(errorCode)
+  result = (ref OSError)(errorCode: errorCode.int32, msg: osErrorMsg(errorCode))
   if additionalInfo.len > 0:
-    if e.msg.len > 0 and e.msg[^1] != '\n': e.msg.add '\n'
-    e.msg.add "Additional info: "
-    e.msg.add additionalInfo
+    if result.msg.len > 0 and result.msg[^1] != '\n': result.msg.add '\n'
+    result.msg.add "Additional info: "
+    result.msg.add additionalInfo
       # don't add trailing `.` etc, which negatively impacts "jump to file" in IDEs.
-  if e.msg == "":
-    e.msg = "unknown OS error"
-  return e
+  if result.msg == "":
+    result.msg = "unknown OS error"
 
 proc raiseOSError*(errorCode: OSErrorCode, additionalInfo = "") {.noinline.} =
   ## Raises an `OSError exception <system.html#OSError>`_.
diff --git a/lib/std/outparams.nim b/lib/std/outparams.nim
index 8a0e5ae67..a471fbaa7 100644
--- a/lib/std/outparams.nim
+++ b/lib/std/outparams.nim
@@ -9,7 +9,7 @@
 
 ## `outParamsAt` macro for easy writing code that works with both 2.0 and 1.x.
 
-import macros
+import std/macros
 
 macro outParamsAt*(positions: static openArray[int]; n: untyped): untyped =
   ## Use this macro to annotate `out` parameters in a portable way.
diff --git a/lib/std/packedsets.nim b/lib/std/packedsets.nim
index 1e2892658..3320558f2 100644
--- a/lib/std/packedsets.nim
+++ b/lib/std/packedsets.nim
@@ -12,17 +12,12 @@
 ##
 ## Supports any Ordinal type.
 ##
-## .. note:: Currently the assignment operator `=` for `PackedSet[A]`
-##   performs some rather meaningless shallow copy. Since Nim currently does
-##   not allow the assignment operator to be overloaded, use the `assign proc
-##   <#assign,PackedSet[A],PackedSet[A]>`_ to get a deep copy.
-##
 ## See also
 ## ========
 ## * `sets module <sets.html>`_ for more general hash sets
 
 import std/private/since
-import hashes
+import std/hashes
 
 when defined(nimPreviewSlimSystem):
   import std/assertions
@@ -114,7 +109,6 @@ proc intSetPut[A](t: var PackedSet[A], key: int): Trunk =
   t.data[h] = result
 
 proc bitincl[A](s: var PackedSet[A], key: int) {.inline.} =
-  var ret: Trunk
   var t = intSetPut(s, key shr TrunkShift)
   var u = key and TrunkMask
   t.bits[u shr IntShift] = t.bits[u shr IntShift] or
@@ -204,6 +198,7 @@ proc contains*[A](s: PackedSet[A], key: A): bool =
     assert B notin letters
 
   if s.elems <= s.a.len:
+    result = false
     for i in 0..<s.elems:
       if s.a[i] == ord(key): return true
   else:
@@ -412,18 +407,9 @@ proc isNil*[A](x: PackedSet[A]): bool {.inline.} =
 
   x.head.isNil and x.elems == 0
 
-proc assign*[A](dest: var PackedSet[A], src: PackedSet[A]) =
+proc `=copy`*[A](dest: var PackedSet[A], src: PackedSet[A]) =
   ## Copies `src` to `dest`.
   ## `dest` does not need to be initialized by the `initPackedSet proc <#initPackedSet>`_.
-  runnableExamples:
-    var
-      a = initPackedSet[int]()
-      b = initPackedSet[int]()
-    b.incl(5)
-    b.incl(7)
-    a.assign(b)
-    assert len(a) == 2
-
   if src.elems <= src.a.len:
     dest.data = @[]
     dest.max = 0
@@ -452,6 +438,19 @@ proc assign*[A](dest: var PackedSet[A], src: PackedSet[A]) =
       dest.data[h] = n
       it = it.next
 
+proc assign*[A](dest: var PackedSet[A], src: PackedSet[A]) {.inline, deprecated.} =
+  ## Copies `src` to `dest`.
+  ## `dest` does not need to be initialized by the `initPackedSet proc <#initPackedSet>`_.
+  runnableExamples:
+    var
+      a = initPackedSet[int]()
+      b = initPackedSet[int]()
+    b.incl(5)
+    b.incl(7)
+    a.assign(b)
+    assert len(a) == 2
+  `=copy`(dest, src)
+
 proc union*[A](s1, s2: PackedSet[A]): PackedSet[A] =
   ## Returns the union of the sets `s1` and `s2`.
   ##
diff --git a/lib/std/paths.nim b/lib/std/paths.nim
index c29096982..664dedd31 100644
--- a/lib/std/paths.nim
+++ b/lib/std/paths.nim
@@ -1,4 +1,7 @@
 ## This module implements path handling.
+##
+## **See also:**
+## * `files module <files.html>`_ for file access
 
 import std/private/osseps
 export osseps
@@ -6,7 +9,7 @@ export osseps
 import std/envvars
 import std/private/osappdirs
 
-import pathnorm
+import std/[pathnorm, hashes, sugar, strutils]
 
 from std/private/ospaths2 import  joinPath, splitPath,
                                   ReadDirEffect, WriteDirEffect,
@@ -22,6 +25,16 @@ export ReadDirEffect, WriteDirEffect
 type
   Path* = distinct string
 
+func hash*(x: Path): Hash =
+  let x = x.string.dup(normalizePath)
+  if FileSystemCaseSensitive:
+    result = x.hash
+  else:
+    result = x.toLowerAscii.hash
+
+template `$`*(x: Path): string =
+  string(x)
+
 func `==`*(x, y: Path): bool {.inline.} =
   ## Compares two paths.
   ##
diff --git a/lib/std/private/dbutils.nim b/lib/std/private/dbutils.nim
deleted file mode 100644
index 0ae3b3702..000000000
--- a/lib/std/private/dbutils.nim
+++ /dev/null
@@ -1,15 +0,0 @@
-import db_common
-
-
-template dbFormatImpl*(formatstr: SqlQuery, dbQuote: proc (s: string): string, args: varargs[string]): string =
-  var res = ""
-  var a = 0
-  for c in items(string(formatstr)):
-    if c == '?':
-      if a == args.len:
-        dbError("""The number of "?" given exceeds the number of parameters present in the query.""")
-      add(res, dbQuote(args[a]))
-      inc(a)
-    else:
-      add(res, c)
-  res
diff --git a/lib/std/private/digitsutils.nim b/lib/std/private/digitsutils.nim
index b3dc5d14f..f2d0d25cb 100644
--- a/lib/std/private/digitsutils.nim
+++ b/lib/std/private/digitsutils.nim
@@ -19,7 +19,7 @@ const
 
 # Inspired by https://engineering.fb.com/2013/03/15/developer-tools/three-optimization-tips-for-c
 # Generates:
-# .. code-block:: nim
+#   ```nim
 #   var res = ""
 #   for i in 0 .. 99:
 #     if i < 10:
@@ -27,14 +27,15 @@ const
 #     else:
 #       res.add $i
 #   doAssert res == digits100
+#   ```
 
 proc utoa2Digits*(buf: var openArray[char]; pos: int; digits: uint32) {.inline.} =
   buf[pos] = digits100[2 * digits]
   buf[pos+1] = digits100[2 * digits + 1]
   #copyMem(buf, unsafeAddr(digits100[2 * digits]), 2 * sizeof((char)))
 
-proc trailingZeros2Digits*(digits: uint32): int32 {.inline.} =
-  return trailingZeros100[digits.int8]
+proc trailingZeros2Digits*(digits: uint32): int {.inline.} =
+  trailingZeros100[digits]
 
 when defined(js):
   proc numToString(a: SomeInteger): cstring {.importjs: "((#) + \"\")".}
@@ -101,9 +102,7 @@ proc addInt*(result: var string; x: int64) {.enforceNoRaises.} =
         num = cast[uint64](x)
       else:
         num = uint64(-x)
-      let base = result.len
-      setLen(result, base + 1)
-      result[base] = '-'
+      result.add '-'
     else:
       num = uint64(x)
     addInt(result, num)
diff --git a/lib/std/private/dragonbox.nim b/lib/std/private/dragonbox.nim
index 2ba22a751..85ffea84a 100644
--- a/lib/std/private/dragonbox.nim
+++ b/lib/std/private/dragonbox.nim
@@ -75,10 +75,10 @@ const
 const
   signMask*: BitsType = not (not BitsType(0) shr 1)
 
-proc constructDouble*(bits: BitsType): Double {.constructor.} =
+proc constructDouble*(bits: BitsType): Double  =
   result.bits = bits
 
-proc constructDouble*(value: ValueType): Double {.constructor.} =
+proc constructDouble*(value: ValueType): Double  =
   result.bits = cast[typeof(result.bits)](value)
 
 proc physicalSignificand*(this: Double): BitsType {.noSideEffect.} =
@@ -1052,7 +1052,7 @@ when false:
   proc memset(x: cstring; ch: char; L: int) {.importc, nodecl.}
   proc memmove(a, b: cstring; L: int) {.importc, nodecl.}
 
-proc utoa8DigitsSkipTrailingZeros*(buf: var openArray[char]; pos: int; digits: uint32): int32 {.inline.} =
+proc utoa8DigitsSkipTrailingZeros*(buf: var openArray[char]; pos: int; digits: uint32): int {.inline.} =
   dragonbox_Assert(digits >= 1)
   dragonbox_Assert(digits <= 99999999'u32)
   let q: uint32 = digits div 10000
@@ -1070,12 +1070,12 @@ proc utoa8DigitsSkipTrailingZeros*(buf: var openArray[char]; pos: int; digits: u
     utoa2Digits(buf, pos + 6, rL)
     return trailingZeros2Digits(if rL == 0: rH else: rL) + (if rL == 0: 2 else: 0)
 
-proc printDecimalDigitsBackwards*(buf: var openArray[char]; pos: int; output64: uint64): int32 {.inline.} =
+proc printDecimalDigitsBackwards*(buf: var openArray[char]; pos: int; output64: uint64): int {.inline.} =
   var pos = pos
   var output64 = output64
-  var tz: int32 = 0
+  var tz = 0
   ##  number of trailing zeros removed.
-  var nd: int32 = 0
+  var nd = 0
   ##  number of decimal digits processed.
   ##  At most 17 digits remaining
   if output64 >= 100000000'u64:
@@ -1220,7 +1220,7 @@ proc formatDigits*[T: Ordinal](buffer: var openArray[char]; pos: T; digits: uint
     ##  dE+123 or d.igitsE+123
     decimalDigitsPosition = 1
   var digitsEnd = pos + int(decimalDigitsPosition + numDigits)
-  let tz: int32 = printDecimalDigitsBackwards(buffer, digitsEnd, digits)
+  let tz = printDecimalDigitsBackwards(buffer, digitsEnd, digits)
   dec(digitsEnd, tz)
   dec(numDigits, tz)
   ##   decimal_exponent += tz; // => decimal_point unchanged.
diff --git a/lib/std/private/gitutils.nim b/lib/std/private/gitutils.nim
index db323bee1..6dc9c8f3b 100644
--- a/lib/std/private/gitutils.nim
+++ b/lib/std/private/gitutils.nim
@@ -4,7 +4,7 @@ internal API for now, API subject to change
 
 # xxx move other git utilities here; candidate for stdlib.
 
-import std/[os, osproc, strutils, tempfiles]
+import std/[os, paths, osproc, strutils, tempfiles]
 
 when defined(nimPreviewSlimSystem):
   import std/[assertions, syncio]
@@ -32,15 +32,8 @@ template retryCall*(maxRetry = 3, backoffDuration = 1.0, call: untyped): bool =
   result
 
 proc isGitRepo*(dir: string): bool =
-  ## This command is used to get the relative path to the root of the repository.
-  ## Using this, we can verify whether a folder is a git repository by checking
-  ## whether the command success and if the output is empty.
-  let (output, status) = execCmdEx("git rev-parse --show-cdup", workingDir = dir)
-  # On Windows there will be a trailing newline on success, remove it.
-  # The value of a successful call typically won't have a whitespace (it's
-  # usually a series of ../), so we know that it's safe to unconditionally
-  # remove trailing whitespaces from the result.
-  result = status == 0 and output.strip() == ""
+  ## Avoid calling git since it depends on /bin/sh existing and fails in Nix.
+  return fileExists(dir/".git/HEAD")
 
 proc diffFiles*(path1, path2: string): tuple[output: string, same: bool] =
   ## Returns a human readable diff of files `path1`, `path2`, the exact form of
diff --git a/lib/std/private/globs.nim b/lib/std/private/globs.nim
index 5e3e33cb4..a6d088558 100644
--- a/lib/std/private/globs.nim
+++ b/lib/std/private/globs.nim
@@ -4,9 +4,9 @@ this can eventually be moved to std/os and `walkDirRec` can be implemented in te
 to avoid duplication
 ]##
 
-import os
+import std/os
 when defined(windows):
-  from strutils import replace
+  from std/strutils import replace
 
 when defined(nimPreviewSlimSystem):
   import std/[assertions, objectdollar]
@@ -60,11 +60,11 @@ proc nativeToUnixPath*(path: string): string =
       result[0] = '/'
       result[1] = path[0]
       if path.len > 2 and path[2] != '\\':
-        doAssert false, "paths like `C:foo` are currently unsupported, path: " & path
+        raiseAssert "paths like `C:foo` are currently unsupported, path: " & path
   when DirSep == '\\':
     result = replace(result, '\\', '/')
 
 when isMainModule:
-  import sugar
+  import std/sugar
   for a in walkDirRecFilter(".", follow = a=>a.path.lastPathPart notin ["nimcache", ".git", "csources_v1", "csources", "bin"]):
     echo a
diff --git a/lib/std/private/jsutils.nim b/lib/std/private/jsutils.nim
index 836b3512a..5f79eab27 100644
--- a/lib/std/private/jsutils.nim
+++ b/lib/std/private/jsutils.nim
@@ -37,13 +37,13 @@ when defined(js):
       let a = array[2, float64].default
       assert jsConstructorName(a) == "Float64Array"
       assert jsConstructorName(a.toJs) == "Float64Array"
-    asm """`result` = `a`.constructor.name"""
+    {.emit: """`result` = `a`.constructor.name;""".}
 
   proc hasJsBigInt*(): bool =
-    asm """`result` = typeof BigInt != 'undefined'"""
+    {.emit: """`result` = typeof BigInt != 'undefined';""".}
 
   proc hasBigUint64Array*(): bool =
-    asm """`result` = typeof BigUint64Array != 'undefined'"""
+    {.emit: """`result` = typeof BigUint64Array != 'undefined';""".}
 
   proc getProtoName*[T](a: T): cstring {.importjs: "Object.prototype.toString.call(#)".} =
     runnableExamples:
@@ -79,5 +79,18 @@ when defined(js):
       assert not "123".toJs.isSafeInteger
       assert 123.isSafeInteger
       assert 123.toJs.isSafeInteger
-      assert 9007199254740991.toJs.isSafeInteger
-      assert not 9007199254740992.toJs.isSafeInteger
+      when false:
+        assert 9007199254740991.toJs.isSafeInteger
+        assert not 9007199254740992.toJs.isSafeInteger
+
+template whenJsNoBigInt64*(no64, yes64): untyped =
+  when defined(js):
+    when compiles(compileOption("jsbigint64")):
+      when compileOption("jsbigint64"):
+        yes64
+      else:
+        no64
+    else:
+      no64
+  else:
+    no64
diff --git a/lib/std/private/miscdollars.nim b/lib/std/private/miscdollars.nim
index 47b788ee9..06fda6fa1 100644
--- a/lib/std/private/miscdollars.nim
+++ b/lib/std/private/miscdollars.nim
@@ -13,21 +13,7 @@ template toLocation*(result: var string, file: string | cstring, line: int, col:
       addInt(result, col)
     result.add ")"
 
-when defined(nimHasIsNamedTuple):
-  proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".}
-else:
-  # for bootstrap; remove after release 1.2
-  proc isNamedTuple(T: typedesc): bool =
-    # Taken from typetraits.
-    when T isnot tuple: result = false
-    else:
-      var t: T
-      for name, _ in t.fieldPairs:
-        when name == "Field0":
-          return compiles(t.Field0)
-        else:
-          return true
-      return false
+proc isNamedTuple(T: typedesc): bool {.magic: "TypeTrait".}
 
 template tupleObjectDollar*[T: tuple | object](result: var string, x: T) =
   result = "("
diff --git a/lib/std/private/osappdirs.nim b/lib/std/private/osappdirs.nim
index 8e6ae00f8..07a6809bb 100644
--- a/lib/std/private/osappdirs.nim
+++ b/lib/std/private/osappdirs.nim
@@ -1,3 +1,5 @@
+## .. importdoc:: paths.nim, dirs.nim
+
 include system/inclrtl
 import std/envvars
 import std/private/ospaths2
@@ -10,6 +12,7 @@ proc getHomeDir*(): string {.rtl, extern: "nos$1",
   ## for the convenience of processing paths coming from user configuration files.
   ##
   ## See also:
+  ## * `getDataDir proc`_
   ## * `getConfigDir proc`_
   ## * `getTempDir proc`_
   ## * `expandTilde proc`_
@@ -22,6 +25,30 @@ proc getHomeDir*(): string {.rtl, extern: "nos$1",
   when defined(windows): return getEnv("USERPROFILE") & "\\"
   else: return getEnv("HOME") & "/"
 
+proc getDataDir*(): string {.rtl, extern: "nos$1"
+  tags: [ReadEnvEffect, ReadIOEffect].} =
+  ## Returns the data directory of the current user for applications.
+  ## 
+  ## On non-Windows OSs, this proc conforms to the XDG Base Directory
+  ## spec. Thus, this proc returns the value of the `XDG_DATA_HOME` environment
+  ## variable if it is set, otherwise it returns the default configuration
+  ## directory ("~/.local/share" or "~/Library/Application Support" on macOS).
+  ## 
+  ## See also:
+  ## * `getHomeDir proc`_
+  ## * `getConfigDir proc`_
+  ## * `getTempDir proc`_
+  ## * `expandTilde proc`_
+  ## * `getCurrentDir proc`_
+  ## * `setCurrentDir proc`_
+  when defined(windows):
+    result = getEnv("APPDATA")
+  elif defined(macosx):
+    result = getEnv("XDG_DATA_HOME", getEnv("HOME") / "Library" / "Application Support")
+  else:
+    result = getEnv("XDG_DATA_HOME", getEnv("HOME") / ".local" / "share")
+  result.normalizePathEnd(trailingSep = true)
+
 proc getConfigDir*(): string {.rtl, extern: "nos$1",
   tags: [ReadEnvEffect, ReadIOEffect].} =
   ## Returns the config directory of the current user for applications.
@@ -36,6 +63,7 @@ proc getConfigDir*(): string {.rtl, extern: "nos$1",
   ##
   ## See also:
   ## * `getHomeDir proc`_
+  ## * `getDataDir proc`_
   ## * `getTempDir proc`_
   ## * `expandTilde proc`_
   ## * `getCurrentDir proc`_
@@ -61,6 +89,7 @@ proc getCacheDir*(): string =
   ## * `getHomeDir proc`_
   ## * `getTempDir proc`_
   ## * `getConfigDir proc`_
+  ## * `getDataDir proc`_
   # follows https://crates.io/crates/platform-dirs
   when defined(windows):
     result = getEnv("LOCALAPPDATA")
diff --git a/lib/std/private/oscommon.nim b/lib/std/private/oscommon.nim
index 5b4e1d7e3..c49d52ef2 100644
--- a/lib/std/private/oscommon.nim
+++ b/lib/std/private/oscommon.nim
@@ -5,6 +5,8 @@ import std/[oserrors]
 when defined(nimPreviewSlimSystem):
   import std/[syncio, assertions, widestrs]
 
+## .. importdoc:: osdirs.nim, os.nim
+
 const weirdTarget* = defined(nimscript) or defined(js)
 
 
@@ -20,9 +22,9 @@ type
 when weirdTarget:
   discard
 elif defined(windows):
-  import winlean, times
+  import std/[winlean, times]
 elif defined(posix):
-  import posix
+  import std/posix
   proc c_rename(oldname, newname: cstring): cint {.
     importc: "rename", header: "<stdio.h>".}
 else:
@@ -45,23 +47,17 @@ else:
 
 
 when defined(windows) and not weirdTarget:
-  when useWinUnicode:
-    template wrapUnary*(varname, winApiProc, arg: untyped) =
-      var varname = winApiProc(newWideCString(arg))
-
-    template wrapBinary*(varname, winApiProc, arg, arg2: untyped) =
-      var varname = winApiProc(newWideCString(arg), arg2)
-    proc findFirstFile*(a: string, b: var WIN32_FIND_DATA): Handle =
-      result = findFirstFileW(newWideCString(a), b)
-    template findNextFile*(a, b: untyped): untyped = findNextFileW(a, b)
-
-    template getFilename*(f: untyped): untyped =
-      $cast[WideCString](addr(f.cFileName[0]))
-  else:
-    template findFirstFile*(a, b: untyped): untyped = findFirstFileA(a, b)
-    template findNextFile*(a, b: untyped): untyped = findNextFileA(a, b)
+  template wrapUnary*(varname, winApiProc, arg: untyped) =
+    var varname = winApiProc(newWideCString(arg))
+
+  template wrapBinary*(varname, winApiProc, arg, arg2: untyped) =
+    var varname = winApiProc(newWideCString(arg), arg2)
+  proc findFirstFile*(a: string, b: var WIN32_FIND_DATA): Handle =
+    result = findFirstFileW(newWideCString(a), b)
+  template findNextFile*(a, b: untyped): untyped = findNextFileW(a, b)
 
-    template getFilename*(f: untyped): untyped = $cast[cstring](addr f.cFileName)
+  template getFilename*(f: untyped): untyped =
+    $cast[WideCString](addr(f.cFileName[0]))
 
   proc skipFindData*(f: WIN32_FIND_DATA): bool {.inline.} =
     # Note - takes advantage of null delimiter in the cstring
@@ -102,12 +98,9 @@ proc tryMoveFSObject*(source, dest: string, isDir: bool): bool {.noWeirdTarget.}
   ## In case of other errors `OSError` is raised.
   ## Returns true in case of success.
   when defined(windows):
-    when useWinUnicode:
-      let s = newWideCString(source)
-      let d = newWideCString(dest)
-      result = moveFileExW(s, d, MOVEFILE_COPY_ALLOWED or MOVEFILE_REPLACE_EXISTING) != 0'i32
-    else:
-      result = moveFileExA(source, dest, MOVEFILE_COPY_ALLOWED or MOVEFILE_REPLACE_EXISTING) != 0'i32
+    let s = newWideCString(source)
+    let d = newWideCString(dest)
+    result = moveFileExW(s, d, MOVEFILE_COPY_ALLOWED or MOVEFILE_REPLACE_EXISTING) != 0'i32
   else:
     result = c_rename(source, dest) == 0'i32
 
@@ -126,7 +119,7 @@ when not defined(windows):
   const maxSymlinkLen* = 1024
 
 proc fileExists*(filename: string): bool {.rtl, extern: "nos$1",
-                                          tags: [ReadDirEffect], noNimJs.} =
+                                          tags: [ReadDirEffect], noNimJs, sideEffect.} =
   ## Returns true if `filename` exists and is a regular file or symlink.
   ##
   ## Directories, device files, named pipes and sockets return false.
@@ -135,10 +128,7 @@ proc fileExists*(filename: string): bool {.rtl, extern: "nos$1",
   ## * `dirExists proc`_
   ## * `symlinkExists proc`_
   when defined(windows):
-    when useWinUnicode:
-      wrapUnary(a, getFileAttributesW, filename)
-    else:
-      var a = getFileAttributesA(filename)
+    wrapUnary(a, getFileAttributesW, filename)
     if a != -1'i32:
       result = (a and FILE_ATTRIBUTE_DIRECTORY) == 0'i32
   else:
@@ -147,7 +137,7 @@ proc fileExists*(filename: string): bool {.rtl, extern: "nos$1",
 
 
 proc dirExists*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect],
-                                     noNimJs.} =
+                                     noNimJs, sideEffect.} =
   ## Returns true if the directory `dir` exists. If `dir` is a file, false
   ## is returned. Follows symlinks.
   ##
@@ -155,10 +145,7 @@ proc dirExists*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect]
   ## * `fileExists proc`_
   ## * `symlinkExists proc`_
   when defined(windows):
-    when useWinUnicode:
-      wrapUnary(a, getFileAttributesW, dir)
-    else:
-      var a = getFileAttributesA(dir)
+    wrapUnary(a, getFileAttributesW, dir)
     if a != -1'i32:
       result = (a and FILE_ATTRIBUTE_DIRECTORY) != 0'i32
   else:
@@ -168,7 +155,7 @@ proc dirExists*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect]
 
 proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1",
                                           tags: [ReadDirEffect],
-                                          noWeirdTarget.} =
+                                          noWeirdTarget, sideEffect.} =
   ## Returns true if the symlink `link` exists. Will return true
   ## regardless of whether the link points to a directory or file.
   ##
@@ -176,10 +163,7 @@ proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1",
   ## * `fileExists proc`_
   ## * `dirExists proc`_
   when defined(windows):
-    when useWinUnicode:
-      wrapUnary(a, getFileAttributesW, link)
-    else:
-      var a = getFileAttributesA(link)
+    wrapUnary(a, getFileAttributesW, link)
     if a != -1'i32:
       # xxx see: bug #16784 (bug9); checking `IO_REPARSE_TAG_SYMLINK`
       # may also be needed.
@@ -195,15 +179,8 @@ when defined(windows) and not weirdTarget:
       flags = flags or FILE_FLAG_OPEN_REPARSE_POINT
     let access = if writeAccess: GENERIC_WRITE else: 0'i32
 
-    when useWinUnicode:
-      result = createFileW(
-        newWideCString(path), access,
-        FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
-        nil, OPEN_EXISTING, flags, 0
-        )
-    else:
-      result = createFileA(
-        path, access,
-        FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
-        nil, OPEN_EXISTING, flags, 0
-        )
+    result = createFileW(
+      newWideCString(path), access,
+      FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
+      nil, OPEN_EXISTING, flags, 0
+      )
diff --git a/lib/std/private/osdirs.nim b/lib/std/private/osdirs.nim
index add9ed424..a44cad7d9 100644
--- a/lib/std/private/osdirs.nim
+++ b/lib/std/private/osdirs.nim
@@ -1,3 +1,5 @@
+## .. importdoc:: osfiles.nim, appdirs.nim, paths.nim
+
 include system/inclrtl
 import std/oserrors
 
@@ -14,9 +16,9 @@ when defined(nimPreviewSlimSystem):
 when weirdTarget:
   discard
 elif defined(windows):
-  import winlean, times
+  import std/[winlean, times]
 elif defined(posix):
-  import posix, times
+  import std/[posix, times]
 
 else:
   {.error: "OS module not ported to your operating system!".}
@@ -326,10 +328,7 @@ iterator walkDirRec*(dir: string,
 
 proc rawRemoveDir(dir: string) {.noWeirdTarget.} =
   when defined(windows):
-    when useWinUnicode:
-      wrapUnary(res, removeDirectoryW, dir)
-    else:
-      var res = removeDirectoryA(dir)
+    wrapUnary(res, removeDirectoryW, dir)
     let lastError = osLastError()
     if res == 0'i32 and lastError.int32 != 3'i32 and
         lastError.int32 != 18'i32 and lastError.int32 != 2'i32:
@@ -394,10 +393,7 @@ proc rawCreateDir(dir: string): bool {.noWeirdTarget.} =
       #echo res
       raiseOSError(osLastError(), dir)
   else:
-    when useWinUnicode:
-      wrapUnary(res, createDirectoryW, dir)
-    else:
-      let res = createDirectoryA(dir)
+    wrapUnary(res, createDirectoryW, dir)
 
     if res != 0'i32:
       result = true
@@ -450,13 +446,17 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1",
     else:
       discard existsOrCreateDir(p)
 
-proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
+proc copyDir*(source, dest: string, skipSpecial = false) {.rtl, extern: "nos$1",
   tags: [ReadDirEffect, WriteIOEffect, ReadIOEffect], benign, noWeirdTarget.} =
   ## Copies a directory from `source` to `dest`.
   ##
   ## On non-Windows OSes, symlinks are copied as symlinks. On Windows, symlinks
   ## are skipped.
   ##
+  ## If `skipSpecial` is true, then (besides all directories) only *regular*
+  ## files (**without** special "file" objects like FIFOs, device files,
+  ## etc) will be copied on Unix.
+  ##
   ## If this fails, `OSError` is raised.
   ##
   ## On the Windows platform this proc will copy the attributes from
@@ -476,16 +476,17 @@ proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
   ## * `createDir proc`_
   ## * `moveDir proc`_
   createDir(dest)
-  for kind, path in walkDir(source):
+  for kind, path in walkDir(source, skipSpecial = skipSpecial):
     var noSource = splitPath(path).tail
     if kind == pcDir:
-      copyDir(path, dest / noSource)
+      copyDir(path, dest / noSource, skipSpecial = skipSpecial)
     else:
       copyFile(path, dest / noSource, {cfSymlinkAsIs})
 
 
 proc copyDirWithPermissions*(source, dest: string,
-                             ignorePermissionErrors = true)
+                             ignorePermissionErrors = true,
+                             skipSpecial = false)
   {.rtl, extern: "nos$1", tags: [ReadDirEffect, WriteIOEffect, ReadIOEffect],
    benign, noWeirdTarget.} =
   ## Copies a directory from `source` to `dest` preserving file permissions.
@@ -493,6 +494,10 @@ proc copyDirWithPermissions*(source, dest: string,
   ## On non-Windows OSes, symlinks are copied as symlinks. On Windows, symlinks
   ## are skipped.
   ##
+  ## If `skipSpecial` is true, then (besides all directories) only *regular*
+  ## files (**without** special "file" objects like FIFOs, device files,
+  ## etc) will be copied on Unix.
+  ##
   ## If this fails, `OSError` is raised. This is a wrapper proc around
   ## `copyDir`_ and `copyFileWithPermissions`_ procs
   ## on non-Windows platforms.
@@ -522,10 +527,10 @@ proc copyDirWithPermissions*(source, dest: string,
     except:
       if not ignorePermissionErrors:
         raise
-  for kind, path in walkDir(source):
+  for kind, path in walkDir(source, skipSpecial = skipSpecial):
     var noSource = splitPath(path).tail
     if kind == pcDir:
-      copyDirWithPermissions(path, dest / noSource, ignorePermissionErrors)
+      copyDirWithPermissions(path, dest / noSource, ignorePermissionErrors, skipSpecial = skipSpecial)
     else:
       copyFileWithPermissions(path, dest / noSource, ignorePermissionErrors, {cfSymlinkAsIs})
 
@@ -559,10 +564,7 @@ proc setCurrentDir*(newDir: string) {.inline, tags: [], noWeirdTarget.} =
   ## * `getTempDir proc`_
   ## * `getCurrentDir proc`_
   when defined(windows):
-    when useWinUnicode:
-      if setCurrentDirectoryW(newWideCString(newDir)) == 0'i32:
-        raiseOSError(osLastError(), newDir)
-    else:
-      if setCurrentDirectoryA(newDir) == 0'i32: raiseOSError(osLastError(), newDir)
+    if setCurrentDirectoryW(newWideCString(newDir)) == 0'i32:
+      raiseOSError(osLastError(), newDir)
   else:
     if chdir(newDir) != 0'i32: raiseOSError(osLastError(), newDir)
diff --git a/lib/std/private/osfiles.nim b/lib/std/private/osfiles.nim
index 301f14600..37d8eabca 100644
--- a/lib/std/private/osfiles.nim
+++ b/lib/std/private/osfiles.nim
@@ -7,6 +7,7 @@ export fileExists
 
 import ospaths2, ossymlinks
 
+## .. importdoc:: osdirs.nim, os.nim
 
 when defined(nimPreviewSlimSystem):
   import std/[syncio, assertions, widestrs]
@@ -14,9 +15,9 @@ when defined(nimPreviewSlimSystem):
 when weirdTarget:
   discard
 elif defined(windows):
-  import winlean
+  import std/winlean
 elif defined(posix):
-  import posix, times
+  import std/[posix, times]
 
   proc toTime(ts: Timespec): times.Time {.inline.} =
     result = initTime(ts.tv_sec.int64, ts.tv_nsec.int)
@@ -83,10 +84,7 @@ proc getFilePermissions*(filename: string): set[FilePermission] {.
     if (a.st_mode and S_IWOTH.Mode) != 0.Mode: result.incl(fpOthersWrite)
     if (a.st_mode and S_IXOTH.Mode) != 0.Mode: result.incl(fpOthersExec)
   else:
-    when useWinUnicode:
-      wrapUnary(res, getFileAttributesW, filename)
-    else:
-      var res = getFileAttributesA(filename)
+    wrapUnary(res, getFileAttributesW, filename)
     if res == -1'i32: raiseOSError(osLastError(), filename)
     if (res and FILE_ATTRIBUTE_READONLY) != 0'i32:
       result = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead,
@@ -135,19 +133,13 @@ proc setFilePermissions*(filename: string, permissions: set[FilePermission],
       if chmod(filename, cast[Mode](p)) != 0:
         raiseOSError(osLastError(), $(filename, permissions))
   else:
-    when useWinUnicode:
-      wrapUnary(res, getFileAttributesW, filename)
-    else:
-      var res = getFileAttributesA(filename)
+    wrapUnary(res, getFileAttributesW, filename)
     if res == -1'i32: raiseOSError(osLastError(), filename)
     if fpUserWrite in permissions:
       res = res and not FILE_ATTRIBUTE_READONLY
     else:
       res = res or FILE_ATTRIBUTE_READONLY
-    when useWinUnicode:
-      wrapBinary(res2, setFileAttributesW, filename, res)
-    else:
-      var res2 = setFileAttributesA(filename, res)
+    wrapBinary(res2, setFileAttributesW, filename, res)
     if res2 == - 1'i32: raiseOSError(osLastError(), $(filename, permissions))
 
 
@@ -163,10 +155,14 @@ when hasCCopyfile:
   proc copyfile_state_alloc(): copyfile_state_t
   proc copyfile_state_free(state: copyfile_state_t): cint
   proc c_copyfile(src, dst: cstring,  state: copyfile_state_t, flags: copyfile_flags_t): cint {.importc: "copyfile".}
-  # replace with `let` pending bootstrap >= 1.4.0
-  var
-    COPYFILE_DATA {.nodecl.}: copyfile_flags_t
-    COPYFILE_XATTR {.nodecl.}: copyfile_flags_t
+  when (NimMajor, NimMinor) >= (1, 4):
+    let
+      COPYFILE_DATA {.nodecl.}: copyfile_flags_t
+      COPYFILE_XATTR {.nodecl.}: copyfile_flags_t
+  else:
+    var
+      COPYFILE_DATA {.nodecl.}: copyfile_flags_t
+      COPYFILE_XATTR {.nodecl.}: copyfile_flags_t
   {.pop.}
 
 type
@@ -177,7 +173,7 @@ type
 
 const copyFlagSymlink = {cfSymlinkAsIs, cfSymlinkFollow, cfSymlinkIgnore}
 
-proc copyFile*(source, dest: string, options = {cfSymlinkFollow}) {.rtl,
+proc copyFile*(source, dest: string, options = {cfSymlinkFollow}; bufferSize = 16_384) {.rtl,
   extern: "nos$1", tags: [ReadDirEffect, ReadIOEffect, WriteIOEffect],
   noWeirdTarget.} =
   ## Copies a file from `source` to `dest`, where `dest.parentDir` must exist.
@@ -206,6 +202,8 @@ proc copyFile*(source, dest: string, options = {cfSymlinkFollow}) {.rtl,
   ## On OSX, `copyfile` C api will be used (available since OSX 10.5) unless
   ## `-d:nimLegacyCopyFile` is used.
   ##
+  ## `copyFile` allows to specify `bufferSize` to improve I/O performance.
+  ##
   ## See also:
   ## * `CopyFlag enum`_
   ## * `copyDir proc`_
@@ -214,20 +212,15 @@ proc copyFile*(source, dest: string, options = {cfSymlinkFollow}) {.rtl,
   ## * `removeFile proc`_
   ## * `moveFile proc`_
 
-  doAssert card(copyFlagSymlink * options) == 1, "There should be exactly " &
-                                                 "one cfSymlink* in options"
+  doAssert card(copyFlagSymlink * options) == 1, "There should be exactly one cfSymlink* in options"
   let isSymlink = source.symlinkExists
   if isSymlink and (cfSymlinkIgnore in options or defined(windows)):
     return
   when defined(windows):
-    when useWinUnicode:
-      let s = newWideCString(source)
-      let d = newWideCString(dest)
-      if copyFileW(s, d, 0'i32) == 0'i32:
-        raiseOSError(osLastError(), $(source, dest))
-    else:
-      if copyFileA(source, dest, 0'i32) == 0'i32:
-        raiseOSError(osLastError(), $(source, dest))
+    let s = newWideCString(source)
+    let d = newWideCString(dest)
+    if copyFileW(s, d, 0'i32) == 0'i32:
+      raiseOSError(osLastError(), $(source, dest))
   else:
     if isSymlink and cfSymlinkAsIs in options:
       createSymlink(expandSymlink(source), dest)
@@ -246,15 +239,21 @@ proc copyFile*(source, dest: string, options = {cfSymlinkFollow}) {.rtl,
         if status2 != 0: raiseOSError(osLastError(), $(source, dest))
       else:
         # generic version of copyFile which works for any platform:
-        const bufSize = 8000 # better for memory manager
         var d, s: File
-        if not open(s, source):raiseOSError(osLastError(), source)
+        if not open(s, source): raiseOSError(osLastError(), source)
         if not open(d, dest, fmWrite):
           close(s)
           raiseOSError(osLastError(), dest)
-        var buf = alloc(bufSize)
+
+        # Hints for kernel-level aggressive sequential low-fragmentation read-aheads:
+        # https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fadvise.html
+        when defined(linux) or defined(osx):
+          discard posix_fadvise(getFileHandle(d), 0.cint, 0.cint, POSIX_FADV_SEQUENTIAL)
+          discard posix_fadvise(getFileHandle(s), 0.cint, 0.cint, POSIX_FADV_SEQUENTIAL)
+
+        var buf = alloc(bufferSize)
         while true:
-          var bytesread = readBuffer(s, buf, bufSize)
+          var bytesread = readBuffer(s, buf, bufferSize)
           if bytesread > 0:
             var byteswritten = writeBuffer(d, buf, bytesread)
             if bytesread != byteswritten:
@@ -262,13 +261,13 @@ proc copyFile*(source, dest: string, options = {cfSymlinkFollow}) {.rtl,
               close(s)
               close(d)
               raiseOSError(osLastError(), dest)
-          if bytesread != bufSize: break
+          if bytesread != bufferSize: break
         dealloc(buf)
         close(s)
         flushFile(d)
         close(d)
 
-proc copyFileToDir*(source, dir: string, options = {cfSymlinkFollow})
+proc copyFileToDir*(source, dir: string, options = {cfSymlinkFollow}; bufferSize = 16_384)
   {.noWeirdTarget, since: (1,3,7).} =
   ## Copies a file `source` into directory `dir`, which must exist.
   ##
@@ -276,12 +275,14 @@ proc copyFileToDir*(source, dir: string, options = {cfSymlinkFollow})
   ## if `source` is a symlink, copies the file symlink points to. `options` is
   ## ignored on Windows: symlinks are skipped.
   ##
+  ## `copyFileToDir` allows to specify `bufferSize` to improve I/O performance.
+  ##
   ## See also:
   ## * `CopyFlag enum`_
   ## * `copyFile proc`_
   if dir.len == 0: # treating "" as "." is error prone
     raise newException(ValueError, "dest is empty")
-  copyFile(source, dir / source.lastPathPart, options)
+  copyFile(source, dir / source.lastPathPart, options, bufferSize)
 
 
 proc copyFileWithPermissions*(source, dest: string,
@@ -333,14 +334,9 @@ when not declared(ENOENT) and not defined(windows):
     var ENOENT {.importc, header: "<errno.h>".}: cint
 
 when defined(windows) and not weirdTarget:
-  when useWinUnicode:
-    template deleteFile(file: untyped): untyped  = deleteFileW(file)
-    template setFileAttributes(file, attrs: untyped): untyped =
-      setFileAttributesW(file, attrs)
-  else:
-    template deleteFile(file: untyped): untyped = deleteFileA(file)
-    template setFileAttributes(file, attrs: untyped): untyped =
-      setFileAttributesA(file, attrs)
+  template deleteFile(file: untyped): untyped  = deleteFileW(file)
+  template setFileAttributes(file, attrs: untyped): untyped =
+    setFileAttributesW(file, attrs)
 
 proc tryRemoveFile*(file: string): bool {.rtl, extern: "nos$1", tags: [WriteDirEffect], noWeirdTarget.} =
   ## Removes the `file`.
@@ -357,10 +353,7 @@ proc tryRemoveFile*(file: string): bool {.rtl, extern: "nos$1", tags: [WriteDirE
   ## * `moveFile proc`_
   result = true
   when defined(windows):
-    when useWinUnicode:
-      let f = newWideCString(file)
-    else:
-      let f = file
+    let f = newWideCString(file)
     if deleteFile(f) == 0:
       result = false
       let err = getLastError()
@@ -412,12 +405,12 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
 
   if not tryMoveFSObject(source, dest, isDir = false):
     when defined(windows):
-      doAssert false
+      raiseAssert "unreachable"
     else:
       # Fallback to copy & del
-      copyFile(source, dest, {cfSymlinkAsIs})
+      copyFileWithPermissions(source, dest, options={cfSymlinkAsIs})
       try:
         removeFile(source)
       except:
         discard tryRemoveFile(dest)
-        raise
\ No newline at end of file
+        raise
diff --git a/lib/std/private/ospaths2.nim b/lib/std/private/ospaths2.nim
index 75c34ecf5..bc69ff725 100644
--- a/lib/std/private/ospaths2.nim
+++ b/lib/std/private/ospaths2.nim
@@ -1,7 +1,7 @@
 include system/inclrtl
 import std/private/since
 
-import strutils, pathnorm
+import std/[strutils, pathnorm]
 import std/oserrors
 
 import oscommon
@@ -10,14 +10,16 @@ export ReadDirEffect, WriteDirEffect
 when defined(nimPreviewSlimSystem):
   import std/[syncio, assertions, widestrs]
 
+## .. importdoc:: osappdirs.nim, osdirs.nim, osseps.nim, os.nim
+
 const weirdTarget = defined(nimscript) or defined(js)
 
 when weirdTarget:
   discard
 elif defined(windows):
-  import winlean
+  import std/winlean
 elif defined(posix):
-  import posix, system/ansi_c
+  import std/posix, system/ansi_c
 else:
   {.error: "OS module not ported to your operating system!".}
 
@@ -252,12 +254,12 @@ proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1", raise
     result = path[0] != ':'
   elif defined(RISCOS):
     result = path[0] == '$'
-  elif defined(posix) or defined(js):
-    # `or defined(js)` wouldn't be needed pending https://github.com/nim-lang/Nim/issues/13469
-    # This works around the problem for posix, but Windows is still broken with nim js -d:nodejs
+  elif defined(posix):
     result = path[0] == '/'
+  elif defined(nodejs):
+    {.emit: [result," = require(\"path\").isAbsolute(",path.cstring,");"].}
   else:
-    doAssert false # if ever hits here, adapt as needed
+    raiseAssert "unreachable" # if ever hits here, adapt as needed
 
 when FileSystemCaseSensitive:
   template `!=?`(a, b: char): bool = a != b
@@ -569,7 +571,7 @@ proc normExt(ext: string): string =
 
 proc searchExtPos*(path: string): int =
   ## Returns index of the `'.'` char in `path` if it signifies the beginning
-  ## of extension. Returns -1 otherwise.
+  ## of the file extension. Returns -1 otherwise.
   ##
   ## See also:
   ## * `splitFile proc`_
@@ -582,15 +584,28 @@ proc searchExtPos*(path: string): int =
     assert searchExtPos("c.nim") == 1
     assert searchExtPos("a/b/c.nim") == 5
     assert searchExtPos("a.b.c.nim") == 5
+    assert searchExtPos(".nim") == -1
+    assert searchExtPos("..nim") == -1
+    assert searchExtPos("a..nim") == 2
 
-  # BUGFIX: do not search until 0! .DS_Store is no file extension!
+  # Unless there is any char that is not `ExtSep` before last `ExtSep` in the file name,
+  # it is not a file extension.
+  const DirSeps = when doslikeFileSystem: {DirSep, AltSep, ':'} else: {DirSep, AltSep}
   result = -1
-  for i in countdown(len(path)-1, 1):
+  var i = path.high
+  while i >= 1:
     if path[i] == ExtSep:
+      break
+    elif path[i] in DirSeps:
+      return -1 # do not skip over path
+    dec i
+
+  for j in countdown(i - 1, 0):
+    if path[j] in DirSeps:
+      return -1
+    elif path[j] != ExtSep:
       result = i
       break
-    elif path[i] in {DirSep, AltSep}:
-      break # do not skip over path
 
 proc splitFile*(path: string): tuple[dir, name, ext: string] {.
   noSideEffect, rtl, extern: "nos$1".} =
@@ -748,9 +763,9 @@ proc cmpPaths*(pathA, pathB: string): int {.
   ## On a case-sensitive filesystem this is done
   ## case-sensitively otherwise case-insensitively. Returns:
   ##
-  ## | 0 if pathA == pathB
-  ## | < 0 if pathA < pathB
-  ## | > 0 if pathA > pathB
+  ## | `0` if pathA == pathB
+  ## | `< 0` if pathA < pathB
+  ## | `> 0` if pathA > pathB
   runnableExamples:
     when defined(macosx):
       assert cmpPaths("foo", "Foo") == 0
@@ -844,33 +859,20 @@ when not defined(nimscript):
       {.emit: "`ret` = process.cwd();".}
       return $ret
     elif defined(js):
-      doAssert false, "use -d:nodejs to have `getCurrentDir` defined"
+      raiseAssert "use -d:nodejs to have `getCurrentDir` defined"
     elif defined(windows):
       var bufsize = MAX_PATH.int32
-      when useWinUnicode:
-        var res = newWideCString("", bufsize)
-        while true:
-          var L = getCurrentDirectoryW(bufsize, res)
-          if L == 0'i32:
-            raiseOSError(osLastError())
-          elif L > bufsize:
-            res = newWideCString("", L)
-            bufsize = L
-          else:
-            result = res$L
-            break
-      else:
-        result = newString(bufsize)
-        while true:
-          var L = getCurrentDirectoryA(bufsize, result)
-          if L == 0'i32:
-            raiseOSError(osLastError())
-          elif L > bufsize:
-            result = newString(L)
-            bufsize = L
-          else:
-            setLen(result, L)
-            break
+      var res = newWideCString(bufsize)
+      while true:
+        var L = getCurrentDirectoryW(bufsize, res)
+        if L == 0'i32:
+          raiseOSError(osLastError())
+        elif L > bufsize:
+          res = newWideCString(L)
+          bufsize = L
+        else:
+          result = res$L
+          break
     else:
       var bufsize = 1024 # should be enough
       result = newString(bufsize)
diff --git a/lib/std/private/osseps.nim b/lib/std/private/osseps.nim
index 1ea587e3c..f2d49d886 100644
--- a/lib/std/private/osseps.nim
+++ b/lib/std/private/osseps.nim
@@ -3,6 +3,8 @@
 
 # Improved based on info in 'compiler/platform.nim'
 
+## .. importdoc:: ospaths2.nim
+
 const
   doslikeFileSystem* = defined(windows) or defined(OS2) or defined(DOS)
 
diff --git a/lib/std/private/ossymlinks.nim b/lib/std/private/ossymlinks.nim
index cb6287bde..c1760c42e 100644
--- a/lib/std/private/ossymlinks.nim
+++ b/lib/std/private/ossymlinks.nim
@@ -10,9 +10,9 @@ when defined(nimPreviewSlimSystem):
 when weirdTarget:
   discard
 elif defined(windows):
-  import winlean, times
+  import std/[winlean, times]
 elif defined(posix):
-  import posix
+  import std/posix
 else:
   {.error: "OS module not ported to your operating system!".}
 
@@ -31,6 +31,7 @@ elif defined(js):
 else:
   {.pragma: noNimJs.}
 
+## .. importdoc:: os.nim
 
 proc createSymlink*(src, dest: string) {.noWeirdTarget.} =
   ## Create a symbolic link at `dest` which points to the item specified
@@ -47,14 +48,10 @@ proc createSymlink*(src, dest: string) {.noWeirdTarget.} =
     const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 2
     # allows anyone with developer mode on to create a link
     let flag = dirExists(src).int32 or SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
-    when useWinUnicode:
-      var wSrc = newWideCString(src)
-      var wDst = newWideCString(dest)
-      if createSymbolicLinkW(wDst, wSrc, flag) == 0 or getLastError() != 0:
-        raiseOSError(osLastError(), $(src, dest))
-    else:
-      if createSymbolicLinkA(dest, src, flag) == 0 or getLastError() != 0:
-        raiseOSError(osLastError(), $(src, dest))
+    var wSrc = newWideCString(src)
+    var wDst = newWideCString(dest)
+    if createSymbolicLinkW(wDst, wSrc, flag) == 0 or getLastError() != 0:
+      raiseOSError(osLastError(), $(src, dest))
   else:
     if symlink(src, dest) != 0:
       raiseOSError(osLastError(), $(src, dest))
@@ -66,14 +63,16 @@ proc expandSymlink*(symlinkPath: string): string {.noWeirdTarget.} =
   ##
   ## See also:
   ## * `createSymlink proc`_
-  when defined(windows):
+  when defined(windows) or defined(nintendoswitch):
     result = symlinkPath
   else:
-    result = newString(maxSymlinkLen)
-    var len = readlink(symlinkPath, result.cstring, maxSymlinkLen)
-    if len < 0:
-      raiseOSError(osLastError(), symlinkPath)
-    if len > maxSymlinkLen:
-      result = newString(len+1)
-      len = readlink(symlinkPath, result.cstring, len)
-    setLen(result, len)
+    var bufLen = 1024
+    while true:
+      result = newString(bufLen)
+      let len = readlink(symlinkPath.cstring, result.cstring, bufLen)
+      if len < 0:
+        raiseOSError(osLastError(), symlinkPath)
+      if len < bufLen:
+        result.setLen(len)
+        break
+      bufLen = bufLen shl 1
diff --git a/lib/std/private/schubfach.nim b/lib/std/private/schubfach.nim
index dad8363ba..b8c85d2bc 100644
--- a/lib/std/private/schubfach.nim
+++ b/lib/std/private/schubfach.nim
@@ -39,10 +39,10 @@ const
   exponentMask: BitsType = maxIeeeExponent shl (significandSize - 1)
   signMask: BitsType = not (not BitsType(0) shr 1)
 
-proc constructSingle(bits: BitsType): Single {.constructor.} =
+proc constructSingle(bits: BitsType): Single  =
   result.bits = bits
 
-proc constructSingle(value: ValueType): Single {.constructor.} =
+proc constructSingle(value: ValueType): Single  =
   result.bits = cast[typeof(result.bits)](value)
 
 proc physicalSignificand(this: Single): BitsType {.noSideEffect.} =
@@ -244,12 +244,12 @@ proc toDecimal32(ieeeSignificand: uint32; ieeeExponent: uint32): FloatingDecimal
 ##  ToChars
 ## ==================================================================================================
 
-proc printDecimalDigitsBackwards[T: Ordinal](buf: var openArray[char]; pos: T; output: uint32): int32 {.inline.} =
+proc printDecimalDigitsBackwards[T: Ordinal](buf: var openArray[char]; pos: T; output: uint32): int {.inline.} =
   var output = output
   var pos = pos
-  var tz: int32 = 0
+  var tz = 0
   ##  number of trailing zeros removed.
-  var nd: int32 = 0
+  var nd = 0
   ##  number of decimal digits processed.
   ##  At most 9 digits remaining
   if output >= 10000:
@@ -355,7 +355,7 @@ proc formatDigits[T: Ordinal](buffer: var openArray[char]; pos: T; digits: uint3
     ##  dE+123 or d.igitsE+123
     decimalDigitsPosition = 1
   var digitsEnd = pos + decimalDigitsPosition + numDigits
-  let tz: int32 = printDecimalDigitsBackwards(buffer, digitsEnd, digits)
+  let tz = printDecimalDigitsBackwards(buffer, digitsEnd, digits)
   dec(digitsEnd, tz)
   dec(numDigits, tz)
   ##   decimal_exponent += tz; // => decimal_point unchanged.
diff --git a/lib/std/private/since.nim b/lib/std/private/since.nim
index 5b22b6391..720120f11 100644
--- a/lib/std/private/since.nim
+++ b/lib/std/private/since.nim
@@ -1,5 +1,5 @@
 ##[
-`since` is used to emulate older versions of nim stdlib with `--useVersion`,
+`since` is used to emulate older versions of nim stdlib,
 see `tuse_version.nim`.
 
 If a symbol `foo` is added in version `(1,3,5)`, use `{.since: (1.3.5).}`, not
@@ -15,19 +15,19 @@ The emulation cannot be 100% faithful and to avoid adding too much complexity,
 template since*(version: (int, int), body: untyped) {.dirty.} =
   ## Evaluates `body` if the ``(NimMajor, NimMinor)`` is greater than
   ## or equal to `version`. Usage:
-  ##
-  ## .. code-block:: Nim
+  ##   ```Nim
   ##   proc fun*() {.since: (1, 3).}
   ##   since (1, 3): fun()
+  ##   ```
   when (NimMajor, NimMinor) >= version:
     body
 
 template since*(version: (int, int, int), body: untyped) {.dirty.} =
   ## Evaluates `body` if ``(NimMajor, NimMinor, NimPatch)`` is greater than 
   ## or equal to `version`. Usage:
-  ##
-  ## .. code-block:: Nim
+  ##   ```Nim
   ##   proc fun*() {.since: (1, 3, 1).}
   ##   since (1, 3, 1): fun()
+  ##   ```
   when (NimMajor, NimMinor, NimPatch) >= version:
     body
diff --git a/lib/std/private/strimpl.nim b/lib/std/private/strimpl.nim
index 6a38cbfd2..f8c9236a5 100644
--- a/lib/std/private/strimpl.nim
+++ b/lib/std/private/strimpl.nim
@@ -93,7 +93,7 @@ func find*(s: cstring, sub: char, start: Natural = 0, last = 0): int =
   if L > 0:
     let found = c_memchr(s[start].unsafeAddr, sub, cast[csize_t](L))
     if not found.isNil:
-      return cast[ByteAddress](found) -% cast[ByteAddress](s)
+      return cast[int](found) -% cast[int](s)
   return -1
 
 func find*(s, sub: cstring, start: Natural = 0, last = 0): int =
@@ -108,6 +108,6 @@ func find*(s, sub: cstring, start: Natural = 0, last = 0): int =
   if last == 0 and s.len > start:
     let found = c_strstr(cast[cstring](s[start].unsafeAddr), sub)
     if not found.isNil:
-      result = cast[ByteAddress](found) -% cast[ByteAddress](s)
+      result = cast[int](found) -% cast[int](s)
     else:
       result = -1
diff --git a/lib/std/private/syslocks.nim b/lib/std/private/syslocks.nim
index ca8897dc2..e19ec2c04 100644
--- a/lib/std/private/syslocks.nim
+++ b/lib/std/private/syslocks.nim
@@ -16,7 +16,7 @@ when defined(windows):
     Handle = int
 
     SysLock* {.importc: "CRITICAL_SECTION",
-              header: "<windows.h>", final, pure.} = object # CRITICAL_SECTION in WinApi
+              header: "<windows.h>", final, pure, byref.} = object # CRITICAL_SECTION in WinApi
       DebugInfo: pointer
       LockCount: int32
       RecursionCount: int32
@@ -24,7 +24,7 @@ when defined(windows):
       LockSemaphore: int
       SpinCount: int
 
-    SysCond* {.importc: "RTL_CONDITION_VARIABLE", header: "<windows.h>".} = object
+    SysCond* {.importc: "RTL_CONDITION_VARIABLE", header: "<windows.h>", byref.} = object
       thePtr {.importc: "Ptr".} : Handle
 
   proc initSysLock*(L: var SysLock) {.importc: "InitializeCriticalSection",
@@ -46,7 +46,7 @@ when defined(windows):
                                     header: "<windows.h>".}
     ## Releases the lock `L`.
 
-  proc deinitSys*(L: var SysLock) {.importc: "DeleteCriticalSection",
+  proc deinitSys*(L: SysLock) {.importc: "DeleteCriticalSection",
                                    header: "<windows.h>".}
 
   proc initializeConditionVariable(
@@ -68,7 +68,7 @@ when defined(windows):
 
   proc initSysCond*(cond: var SysCond) {.inline.} =
     initializeConditionVariable(cond)
-  proc deinitSysCond*(cond: var SysCond) {.inline.} =
+  proc deinitSysCond*(cond: SysCond) {.inline.} =
     discard
   proc waitSysCond*(cond: var SysCond, lock: var SysLock) =
     discard sleepConditionVariableCS(cond, lock, -1'i32)
@@ -83,13 +83,13 @@ elif defined(genode):
               header: Header.} = object
 
   proc initSysLock*(L: var SysLock) = discard
-  proc deinitSys*(L: var SysLock) = discard
+  proc deinitSys*(L: SysLock) = discard
   proc acquireSys*(L: var SysLock) {.noSideEffect, importcpp.}
   proc tryAcquireSys*(L: var SysLock): bool {.noSideEffect, importcpp.}
   proc releaseSys*(L: var SysLock) {.noSideEffect, importcpp.}
 
   proc initSysCond*(L: var SysCond) = discard
-  proc deinitSysCond*(L: var SysCond) = discard
+  proc deinitSysCond*(L: SysCond) = discard
   proc waitSysCond*(cond: var SysCond, lock: var SysLock) {.
     noSideEffect, importcpp.}
   proc signalSysCond*(cond: var SysCond) {.
@@ -101,7 +101,7 @@ else:
   type
     SysLockObj {.importc: "pthread_mutex_t", pure, final,
                header: """#include <sys/types.h>
-                          #include <pthread.h>""".} = object
+                          #include <pthread.h>""", byref.} = object
       when defined(linux) and defined(amd64):
         abi: array[40 div sizeof(clong), clong]
 
@@ -113,7 +113,7 @@ else:
 
     SysCondObj {.importc: "pthread_cond_t", pure, final,
                header: """#include <sys/types.h>
-                          #include <pthread.h>""".} = object
+                          #include <pthread.h>""", byref.} = object
       when defined(linux) and defined(amd64):
         abi: array[48 div sizeof(clonglong), clonglong]
 
@@ -127,7 +127,7 @@ else:
 
   proc initSysLockAux(L: var SysLockObj, attr: ptr SysLockAttr) {.
     importc: "pthread_mutex_init", header: "<pthread.h>", noSideEffect.}
-  proc deinitSysAux(L: var SysLockObj) {.noSideEffect,
+  proc deinitSysAux(L: SysLockObj) {.noSideEffect,
     importc: "pthread_mutex_destroy", header: "<pthread.h>".}
 
   proc acquireSysAux(L: var SysLockObj) {.noSideEffect,
@@ -156,7 +156,7 @@ else:
       L = cast[SysLock](c_malloc(csize_t(sizeof(SysLockObj))))
       initSysLockAux(L[], attr)
 
-    proc deinitSys*(L: var SysLock) =
+    proc deinitSys*(L: SysLock) =
       deinitSysAux(L[])
       c_free(L)
 
@@ -173,7 +173,7 @@ else:
 
     template initSysLock*(L: var SysLock, attr: ptr SysLockAttr = nil) =
       initSysLockAux(L, attr)
-    template deinitSys*(L: var SysLock) =
+    template deinitSys*(L: SysLock) =
       deinitSysAux(L)
     template acquireSys*(L: var SysLock) =
       acquireSysAux(L)
@@ -193,7 +193,7 @@ else:
   # locks
   proc initSysCondAux(cond: var SysCondObj, cond_attr: ptr SysCondAttr = nil) {.
     importc: "pthread_cond_init", header: "<pthread.h>", noSideEffect.}
-  proc deinitSysCondAux(cond: var SysCondObj) {.noSideEffect,
+  proc deinitSysCondAux(cond: SysCondObj) {.noSideEffect,
     importc: "pthread_cond_destroy", header: "<pthread.h>".}
 
   proc waitSysCondAux(cond: var SysCondObj, lock: var SysLockObj): cint {.
@@ -208,7 +208,7 @@ else:
       cond = cast[SysCond](c_malloc(csize_t(sizeof(SysCondObj))))
       initSysCondAux(cond[], cond_attr)
 
-    proc deinitSysCond*(cond: var SysCond) =
+    proc deinitSysCond*(cond: SysCond) =
       deinitSysCondAux(cond[])
       c_free(cond)
 
@@ -221,7 +221,7 @@ else:
   else:
     template initSysCond*(cond: var SysCond, cond_attr: ptr SysCondAttr = nil) =
       initSysCondAux(cond, cond_attr)
-    template deinitSysCond*(cond: var SysCond) =
+    template deinitSysCond*(cond: SysCond) =
       deinitSysCondAux(cond)
 
     template waitSysCond*(cond: var SysCond, lock: var SysLock) =
diff --git a/lib/std/private/underscored_calls.nim b/lib/std/private/underscored_calls.nim
index f0bcbcc74..f853572b5 100644
--- a/lib/std/private/underscored_calls.nim
+++ b/lib/std/private/underscored_calls.nim
@@ -10,7 +10,9 @@
 
 ## This is an internal helper module. Do not use.
 
-import macros
+import std/macros
+
+proc underscoredCalls*(result, calls, arg0: NimNode)
 
 proc underscoredCall(n, arg0: NimNode): NimNode =
   proc underscorePos(n: NimNode): int =
@@ -19,13 +21,19 @@ proc underscoredCall(n, arg0: NimNode): NimNode =
     return 0
 
   if n.kind in nnkCallKinds:
-    result = copyNimNode(n)
-    result.add n[0]
+    if n[0].kind in {nnkIdent, nnkSym} and n[0].eqIdent("with"):
+      expectKind n[1], {nnkIdent, nnkSym}
 
-    let u = underscorePos(n)
-    for i in 1..u-1: result.add n[i]
-    result.add arg0
-    for i in u+1..n.len-1: result.add n[i]
+      result = newStmtList()
+      underscoredCalls(result, n[2 .. ^1].newStmtList, newDotExpr(arg0, n[1]))
+    else:
+      result = copyNimNode(n)
+      result.add n[0]
+
+      let u = underscorePos(n)
+      for i in 1..u-1: result.add n[i]
+      result.add arg0
+      for i in u+1..n.len-1: result.add n[i]
   elif n.kind in {nnkAsgn, nnkExprEqExpr}:
     var field = n[0]
     if n[0].kind == nnkDotExpr and n[0][0].eqIdent("_"):
diff --git a/lib/std/private/win_setenv.nim b/lib/std/private/win_setenv.nim
index 303889a40..66e199dfe 100644
--- a/lib/std/private/win_setenv.nim
+++ b/lib/std/private/win_setenv.nim
@@ -33,25 +33,25 @@ else:
     # same as winlean.setEnvironmentVariableA
 
   proc c_getenv(varname: cstring): cstring {.importc: "getenv", header: "<stdlib.h>".}
-  proc c_wputenv(envstring: WideCString): cint {.importc: "_wputenv", header: "<stdlib.h>".}
-  proc c_wgetenv(varname: WideCString): WideCString {.importc: "_wgetenv", header: "<stdlib.h>".}
+  proc c_wputenv(envstring: ptr wchar_t): cint {.importc: "_wputenv", header: "<stdlib.h>".}
+  proc c_wgetenv(varname: ptr wchar_t): ptr wchar_t {.importc: "_wgetenv", header: "<stdlib.h>".}
 
   var errno {.importc, header: "<errno.h>".}: cint
   var genviron {.importc: "_environ".}: ptr ptr char
     # xxx `ptr UncheckedArray[WideCString]` did not work
 
-  proc wcstombs(wcstr: ptr char, mbstr: WideCString, count: csize_t): csize_t {.importc, header: "<stdlib.h>".}
+  proc wcstombs(wcstr: ptr char, mbstr: ptr wchar_t, count: csize_t): csize_t {.importc, header: "<stdlib.h>".}
     # xxx cint vs errno_t?
 
   proc setEnvImpl*(name: string, value: string, overwrite: cint): cint =
     const EINVAL = cint(22)
-    let wideName = newWideCString(name)
-    if overwrite == 0 and c_wgetenv(wideName) != nil:
+    let wideName: WideCString = newWideCString(name)
+    if overwrite == 0 and c_wgetenv(cast[ptr wchar_t](wideName)) != nil:
       return 0
 
     if value != "":
-      let envstring = name & "=" & value
-      let e = c_wputenv(newWideCString(envstring))
+      let envstring: WideCString = newWideCString(name & "=" & value)
+      let e = c_wputenv(cast[ptr wchar_t](envstring))
       if e != 0:
         errno = EINVAL
         return -1
@@ -62,19 +62,19 @@ else:
     SetEnvironmentVariableA doesn't update `_environ`,
     so we have to do these terrible things.
     ]#
-    let envstring = name & "=  "
-    if c_wputenv(newWideCString(envstring)) != 0:
+    let envstring: WideCString = newWideCString(name & "=  ")
+    if c_wputenv(cast[ptr wchar_t](envstring)) != 0:
       errno = EINVAL
       return -1
     # Here lies the documentation we blatently ignore to make this work.
-    var s = c_wgetenv(wideName)
+    var s = cast[WideCString](c_wgetenv(cast[ptr wchar_t](wideName)))
     s[0] = Utf16Char('\0')
     #[
     This would result in a double null termination, which normally signifies the
     end of the environment variable list, so we stick a completely empty
     environment variable into the list instead.
     ]#
-    s = c_wgetenv(wideName)
+    s = cast[WideCString](c_wgetenv(cast[ptr wchar_t](wideName)))
     s[1] = Utf16Char('=')
     #[
     If genviron is null, the MBCS environment has not been initialized
@@ -88,12 +88,12 @@ else:
       # in the current codepage. Skip updating MBCS environment in this case.
       # For some reason, second `wcstombs` can find non-convertible characters
       # that the first `wcstombs` cannot.
-      let requiredSizeS = wcstombs(nil, wideName, 0)
+      let requiredSizeS = wcstombs(nil, cast[ptr wchar_t](wideName), 0)
       if requiredSizeS != high(csize_t):
         let requiredSize = requiredSizeS.int
         var buf = newSeq[char](requiredSize + 1)
         let buf2 = buf[0].addr
-        if wcstombs(buf2, wideName, csize_t(requiredSize + 1)) != high(csize_t):
+        if wcstombs(buf2, cast[ptr wchar_t](wideName), csize_t(requiredSize + 1)) != high(csize_t):
           var ptrToEnv = c_getenv(cast[cstring](buf2))
           ptrToEnv[0] = '\0'
           ptrToEnv = c_getenv(cast[cstring](buf2))
diff --git a/lib/std/setutils.nim b/lib/std/setutils.nim
index 4664d6dcc..8e7bc6a92 100644
--- a/lib/std/setutils.nim
+++ b/lib/std/setutils.nim
@@ -14,7 +14,7 @@
 ## * `std/packedsets <packedsets.html>`_
 ## * `std/sets <sets.html>`_
 
-import typetraits, macros
+import std/[typetraits, macros]
 
 #[
   type SetElement* = char|byte|bool|int16|uint16|enum|uint8|int8
diff --git a/lib/std/sha1.nim b/lib/std/sha1.nim
index 50175024c..213af4229 100644
--- a/lib/std/sha1.nim
+++ b/lib/std/sha1.nim
@@ -26,8 +26,11 @@ runnableExamples("-r:off"):
     b = parseSecureHash("10DFAEBF6BFDBC7939957068E2EFACEC4972933C")
   assert a == b, "files don't match"
 
-import strutils
-from endians import bigEndian32, bigEndian64
+
+{.deprecated: "use command `nimble install checksums` and import `checksums/sha1` instead".}
+
+import std/strutils
+from std/endians import bigEndian32, bigEndian64
 
 when defined(nimPreviewSlimSystem):
   import std/syncio
@@ -281,4 +284,4 @@ proc `==`*(a, b: SecureHash): bool =
 
 proc isValidSha1Hash*(s: string): bool =
   ## Checks if a string is a valid sha1 hash sum.
-  s.len == 40 and allCharsInSet(s, HexDigits)
+  s.len == 40 and allCharsInSet(s, HexDigits)
\ No newline at end of file
diff --git a/lib/std/socketstreams.nim b/lib/std/socketstreams.nim
index 5c882858d..45e906795 100644
--- a/lib/std/socketstreams.nim
+++ b/lib/std/socketstreams.nim
@@ -31,39 +31,40 @@
 ## Examples
 ## ========
 ##
-## .. code-block:: Nim
-##  import std/socketstreams
+##   ```Nim
+##   import std/socketstreams
 ##
-##  var
-##    socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
-##    stream = newReadSocketStream(socket)
-##  socket.sendTo("127.0.0.1", Port(12345), "SOME REQUEST")
-##  echo stream.readLine() # Will call `recv`
-##  stream.setPosition(0)
-##  echo stream.readLine() # Will return the read line from the buffer
-##  stream.resetStream() # Buffer is now empty, position is 0
-##  echo stream.readLine() # Will call `recv` again
-##  stream.close() # Closes the socket
+##   var
+##     socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
+##     stream = newReadSocketStream(socket)
+##   socket.sendTo("127.0.0.1", Port(12345), "SOME REQUEST")
+##   echo stream.readLine() # Will call `recv`
+##   stream.setPosition(0)
+##   echo stream.readLine() # Will return the read line from the buffer
+##   stream.resetStream() # Buffer is now empty, position is 0
+##   echo stream.readLine() # Will call `recv` again
+##   stream.close() # Closes the socket
+##   ```
 ##
-## .. code-block:: Nim
+##   ```Nim
+##   import std/socketstreams
 ##
-##  import std/socketstreams
-##
-##  var socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
-##  socket.connect("127.0.0.1", Port(12345))
-##  var sendStream = newWriteSocketStream(socket)
-##  sendStream.write "NOM"
-##  sendStream.setPosition(1)
-##  echo sendStream.peekStr(2) # OM
-##  sendStream.write "I"
-##  sendStream.setPosition(0)
-##  echo sendStream.readStr(3) # NIM
-##  echo sendStream.getPosition() # 3
-##  sendStream.flush() # This actually performs the writing to the socket
-##  sendStream.setPosition(1)
-##  sendStream.write "I" # Throws an error as we can't write into an already sent buffer
-
-import net, streams
+##   var socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
+##   socket.connect("127.0.0.1", Port(12345))
+##   var sendStream = newWriteSocketStream(socket)
+##   sendStream.write "NOM"
+##   sendStream.setPosition(1)
+##   echo sendStream.peekStr(2) # OM
+##   sendStream.write "I"
+##   sendStream.setPosition(0)
+##   echo sendStream.readStr(3) # NIM
+##   echo sendStream.getPosition() # 3
+##   sendStream.flush() # This actually performs the writing to the socket
+##   sendStream.setPosition(1)
+##   sendStream.write "I" # Throws an error as we can't write into an already sent buffer
+##   ```
+
+import std/[net, streams]
 
 type
   ReadSocketStream* = ref ReadSocketStreamObj
@@ -146,7 +147,7 @@ proc wsFlush(s: Stream) =
   s.lastFlush = s.buf.len
 
 proc rsClose(s: Stream) =
-  {.cast(tags: []).}:
+  {.cast(raises: [IOError, OSError]), cast(tags: []).}: # todo fixme maybe do something?
     var s = ReadSocketStream(s)
     s.data.close()
 
diff --git a/lib/std/staticos.nim b/lib/std/staticos.nim
new file mode 100644
index 000000000..2617c6913
--- /dev/null
+++ b/lib/std/staticos.nim
@@ -0,0 +1,13 @@
+## This module implements path handling like os module but works at only compile-time.
+## This module works even when cross compiling to OS that is not supported by os module.
+
+proc staticFileExists*(filename: string): bool {.compileTime.} =
+  ## Returns true if `filename` exists and is a regular file or symlink.
+  ##
+  ## Directories, device files, named pipes and sockets return false.
+  discard
+
+proc staticDirExists*(dir: string): bool {.compileTime.} =
+  ## Returns true if the directory `dir` exists. If `dir` is a file, false
+  ## is returned. Follows symlinks.
+  discard
diff --git a/lib/std/strbasics.nim b/lib/std/strbasics.nim
index be1dd7a58..b2c36a4be 100644
--- a/lib/std/strbasics.nim
+++ b/lib/std/strbasics.nim
@@ -23,8 +23,8 @@ proc add*(x: var string, y: openArray[char]) =
   # Use `{.noalias.}` ?
   let n = x.len
   x.setLen n + y.len
-    # pending https://github.com/nim-lang/Nim/issues/14655#issuecomment-643671397
-    # use x.setLen(n + y.len, isInit = false)
+    # pending #19727
+    # setLen unnecessarily zeros memory
   var i = 0
   while i < y.len:
     x[n + i] = y[i]
diff --git a/lib/std/symlinks.nim b/lib/std/symlinks.nim
index 9e77bbe2a..dbe908612 100644
--- a/lib/std/symlinks.nim
+++ b/lib/std/symlinks.nim
@@ -1,11 +1,12 @@
 ## This module implements symlink (symbolic link) handling.
 
-from paths import Path, ReadDirEffect
+## .. importdoc:: os.nim
 
-from std/private/ossymlinks import symlinkExists, createSymlink, expandSymlink
+from std/paths import Path, ReadDirEffect
 
+from std/private/ossymlinks import symlinkExists, createSymlink, expandSymlink
 
-proc symlinkExists*(link: Path): bool {.inline, tags: [ReadDirEffect].} =
+proc symlinkExists*(link: Path): bool {.inline, tags: [ReadDirEffect], sideEffect.} =
   ## Returns true if the symlink `link` exists. Will return true
   ## regardless of whether the link points to a directory or file.
   result = symlinkExists(link.string)
diff --git a/lib/std/syncio.nim b/lib/std/syncio.nim
index 2b5ea6a3c..c34a025af 100644
--- a/lib/std/syncio.nim
+++ b/lib/std/syncio.nim
@@ -38,8 +38,8 @@ type
                          ## at the end. If the file does not exist, it
                          ## will be created.
 
-  FileHandle* = cint ## type that represents an OS file handle; this is
-                      ## useful for low-level file access
+  FileHandle* = cint ## The type that represents an OS file handle; this is
+                      ## useful for low-level file access.
 
   FileSeekPos* = enum ## Position relative to which seek should happen.
                       # The values are ordered so that they match with stdio
@@ -151,14 +151,11 @@ proc c_fprintf(f: File, frmt: cstring): cint {.
 proc c_fputc(c: char, f: File): cint {.
   importc: "fputc", header: "<stdio.h>".}
 
-template sysFatal(exc, msg) =
-  raise newException(exc, msg)
-
 proc raiseEIO(msg: string) {.noinline, noreturn.} =
-  sysFatal(IOError, msg)
+  raise newException(IOError, msg)
 
 proc raiseEOF() {.noinline, noreturn.} =
-  sysFatal(EOFError, "EOF reached")
+  raise newException(EOFError, "EOF reached")
 
 proc strerror(errnum: cint): cstring {.importc, header: "<string.h>".}
 
@@ -246,7 +243,7 @@ when defined(windows):
     # machine. We also enable `setConsoleOutputCP(65001)` now by default.
     # But we cannot call printf directly as the string might contain \0.
     # So we have to loop over all the sections separated by potential \0s.
-    var i = c_fprintf(f, "%s", s)
+    var i = int c_fprintf(f, "%s", s)
     while i < s.len:
       if s[i] == '\0':
         let w = c_fputc('\0', f)
@@ -323,7 +320,7 @@ elif defined(windows):
 const
   BufSize = 4000
 
-proc close*(f: File) {.tags: [], gcsafe.} =
+proc close*(f: File) {.tags: [], gcsafe, sideEffect.} =
   ## Closes the file.
   if not f.isNil:
     discard c_fclose(f)
@@ -359,12 +356,12 @@ proc getOsFileHandle*(f: File): FileHandle =
 
 when defined(nimdoc) or (defined(posix) and not defined(nimscript)) or defined(windows):
   proc setInheritable*(f: FileHandle, inheritable: bool): bool =
-    ## control whether a file handle can be inherited by child processes. Returns
+    ## Controls whether a file handle can be inherited by child processes. Returns
     ## `true` on success. This requires the OS file handle, which can be
     ## retrieved via `getOsFileHandle <#getOsFileHandle,File>`_.
     ##
     ## This procedure is not guaranteed to be available for all platforms. Test for
-    ## availability with `declared() <system.html#declared,untyped>`.
+    ## availability with `declared() <system.html#declared,untyped>`_.
     when SupportIoctlInheritCtl:
       result = c_ioctl(f, if inheritable: FIONCLEX else: FIOCLEX) != -1
     elif defined(freertos) or defined(zephyr):
@@ -390,7 +387,7 @@ proc readLine*(f: File, line: var string): bool {.tags: [ReadIOEffect],
   proc c_memchr(s: pointer, c: cint, n: csize_t): pointer {.
     importc: "memchr", header: "<string.h>".}
 
-  when defined(windows) and not defined(useWinAnsi):
+  when defined(windows):
     proc readConsole(hConsoleInput: FileHandle, lpBuffer: pointer,
                      nNumberOfCharsToRead: int32,
                      lpNumberOfCharsRead: ptr int32,
@@ -422,7 +419,7 @@ proc readLine*(f: File, line: var string): bool {.tags: [ReadIOEffect],
     if f.isatty:
       const numberOfCharsToRead = 2048
       var numberOfCharsRead = 0'i32
-      var buffer = newWideCString("", numberOfCharsToRead)
+      var buffer = newWideCString(numberOfCharsToRead)
       if readConsole(getOsFileHandle(f), addr(buffer[0]),
         numberOfCharsToRead, addr(numberOfCharsRead), nil) == 0:
         var error = getLastError()
@@ -480,15 +477,16 @@ proc readLine*(f: File, line: var string): bool {.tags: [ReadIOEffect],
     let m = c_memchr(addr line[pos], '\L'.ord, cast[csize_t](sp))
     if m != nil:
       # \l found: Could be our own or the one by fgets, in any case, we're done
-      var last = cast[ByteAddress](m) - cast[ByteAddress](addr line[0])
+      var last = cast[int](m) - cast[int](addr line[0])
       if last > 0 and line[last-1] == '\c':
         line.setLen(last-1)
         return last > 1 or fgetsSuccess
-        # We have to distinguish between two possible cases:
+      elif last > 0 and line[last-1] == '\0':
+        # We have to distinguish among three possible cases:
         # \0\l\0 => line ending in a null character.
         # \0\l\l => last line without newline, null was put there by fgets.
-      elif last > 0 and line[last-1] == '\0':
-        if last < pos + sp - 1 and line[last+1] != '\0':
+        #   \0\l => last line without newline, null was put there by fgets.
+        if last >= pos + sp - 1 or line[last+1] != '\0': # bug #21273
           dec last
       line.setLen(last)
       return last > 0 or fgetsSuccess
@@ -611,7 +609,7 @@ proc writeLine*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
 
 # interface to the C procs:
 
-when defined(windows) and not defined(useWinAnsi):
+when defined(windows):
   when defined(cpp):
     proc wfopen(filename, mode: WideCString): pointer {.
       importcpp: "_wfopen((const wchar_t*)#, (const wchar_t*)#)", nodecl.}
@@ -650,6 +648,9 @@ const
         ""
     else:
       ""
+  RawFormatOpen: array[FileMode, cstring] = [
+    # used for open by FileHandle, which calls `fdopen`
+    cstring("rb"), "wb", "w+b", "r+b", "ab"]
   FormatOpen: array[FileMode, cstring] = [
     cstring("rb" & NoInheritFlag), "wb" & NoInheritFlag, "w+b" & NoInheritFlag,
     "r+b" & NoInheritFlag, "ab" & NoInheritFlag
@@ -751,7 +752,7 @@ proc open*(f: var File, filehandle: FileHandle,
         filehandle) else: filehandle
     if not setInheritable(oshandle, false):
       return false
-  f = c_fdopen(filehandle, FormatOpen[mode])
+  f = c_fdopen(filehandle, RawFormatOpen[mode])
   result = f != nil
 
 proc open*(filename: string,
@@ -763,9 +764,9 @@ proc open*(filename: string,
   ##
   ## The file handle associated with the resulting `File` is not inheritable.
   if not open(result, filename, mode, bufSize):
-    sysFatal(IOError, "cannot open: " & filename)
+    raise newException(IOError, "cannot open: " & filename)
 
-proc setFilePos*(f: File, pos: int64, relativeTo: FileSeekPos = fspSet) {.benign.} =
+proc setFilePos*(f: File, pos: int64, relativeTo: FileSeekPos = fspSet) {.benign, sideEffect.} =
   ## Sets the position of the file pointer that is used for read/write
   ## operations. The file's first byte has the index zero.
   if c_fseek(f, pos, cint(relativeTo)) != 0:
@@ -851,7 +852,7 @@ proc readFile*(filename: string): string {.tags: [ReadIOEffect], benign.} =
     finally:
       close(f)
   else:
-    sysFatal(IOError, "cannot open: " & filename)
+    raise newException(IOError, "cannot open: " & filename)
 
 proc writeFile*(filename, content: string) {.tags: [WriteIOEffect], benign.} =
   ## Opens a file named `filename` for writing. Then writes the
@@ -864,7 +865,7 @@ proc writeFile*(filename, content: string) {.tags: [WriteIOEffect], benign.} =
     finally:
       close(f)
   else:
-    sysFatal(IOError, "cannot open: " & filename)
+    raise newException(IOError, "cannot open: " & filename)
 
 proc writeFile*(filename: string, content: openArray[byte]) {.since: (1, 1).} =
   ## Opens a file named `filename` for writing. Then writes the
@@ -873,7 +874,7 @@ proc writeFile*(filename: string, content: openArray[byte]) {.since: (1, 1).} =
   var f: File = nil
   if open(f, filename, fmWrite):
     try:
-      f.writeBuffer(unsafeAddr content[0], content.len)
+      discard f.writeBuffer(unsafeAddr content[0], content.len)
     finally:
       close(f)
   else:
@@ -894,7 +895,7 @@ proc readLines*(filename: string, n: Natural): seq[string] =
     finally:
       close(f)
   else:
-    sysFatal(IOError, "cannot open: " & filename)
+    raise newException(IOError, "cannot open: " & filename)
 
 template readLines*(filename: string): seq[
     string] {.deprecated: "use readLines with two arguments".} =
diff --git a/lib/std/sysatomics.nim b/lib/std/sysatomics.nim
index b7ccb4092..2f203b3eb 100644
--- a/lib/std/sysatomics.nim
+++ b/lib/std/sysatomics.nim
@@ -15,7 +15,7 @@ when defined(nimPreviewSlimSystem):
 
 const
   hasThreadSupport = compileOption("threads") and not defined(nimscript)
-const someGcc = defined(gcc) or defined(llvm_gcc) or defined(clang)
+const someGcc = defined(gcc) or defined(llvm_gcc) or defined(clang) or defined(nintendoswitch)
 const someVcc = defined(vcc) or defined(clang_cl)
 
 type
@@ -265,6 +265,7 @@ else:
 
 
 proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, discardable, raises: [], tags: [].} =
+  ## Atomically increments the integer by some `x`. It returns the new value.
   when someGcc and hasThreadSupport:
     result = atomicAddFetch(memLoc.addr, x, ATOMIC_SEQ_CST)
   elif someVcc and hasThreadSupport:
@@ -275,6 +276,7 @@ proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, discardable, raises:
     result = memLoc
 
 proc atomicDec*(memLoc: var int, x: int = 1): int {.inline, discardable, raises: [], tags: [].} =
+  ## Atomically decrements the integer by some `x`. It returns the new value.
   when someGcc and hasThreadSupport:
     when declared(atomicSubFetch):
       result = atomicSubFetch(memLoc.addr, x, ATOMIC_SEQ_CST)
@@ -361,7 +363,7 @@ elif someGcc or defined(tcc):
 elif defined(icl):
   proc cpuRelax* {.importc: "_mm_pause", header: "xmmintrin.h".}
 elif false:
-  from os import sleep
+  from std/os import sleep
 
   proc cpuRelax* {.inline.} = os.sleep(1)
 
diff --git a/lib/std/sysrand.nim b/lib/std/sysrand.nim
index eeaa23d72..6f2c6b0c1 100644
--- a/lib/std/sysrand.nim
+++ b/lib/std/sysrand.nim
@@ -60,7 +60,7 @@ when not defined(js):
   import std/oserrors
 
 when defined(posix):
-  import posix
+  import std/posix
 
 when defined(nimPreviewSlimSystem):
   import std/assertions
@@ -168,8 +168,10 @@ elif defined(windows):
     result = randomBytes(addr dest[0], size)
 
 elif defined(linux) and not defined(nimNoGetRandom) and not defined(emscripten):
-  # TODO using let, pending bootstrap >= 1.4.0
-  var SYS_getrandom {.importc: "SYS_getrandom", header: "<sys/syscall.h>".}: clong
+  when (NimMajor, NimMinor) >= (1, 4):
+    let SYS_getrandom {.importc: "SYS_getrandom", header: "<sys/syscall.h>".}: clong
+  else:
+    var SYS_getrandom {.importc: "SYS_getrandom", header: "<sys/syscall.h>".}: clong
   const syscallHeader = """#include <unistd.h>
 #include <sys/syscall.h>"""
 
@@ -190,12 +192,11 @@ elif defined(linux) and not defined(nimNoGetRandom) and not defined(emscripten):
     while result < size:
       let readBytes = syscall(SYS_getrandom, addr dest[result], cint(size - result), 0).int
       if readBytes == 0:
-        doAssert false
+        raiseAssert "unreachable"
       elif readBytes > 0:
         inc(result, readBytes)
       else:
-        if osLastError().int in {EINTR, EAGAIN}:
-          discard
+        if osLastError().cint in [EINTR, EAGAIN]: discard
         else:
           result = -1
           break
diff --git a/lib/std/tasks.nim b/lib/std/tasks.nim
index 055ddf144..7e59747f5 100644
--- a/lib/std/tasks.nim
+++ b/lib/std/tasks.nim
@@ -11,7 +11,6 @@
 ## A `Task` should be only owned by a single Thread, it cannot be shared by threads.
 
 import std/[macros, isolation, typetraits]
-import system/ansi_c
 
 when defined(nimPreviewSlimSystem):
   import std/assertions
@@ -62,24 +61,33 @@ when compileOption("threads"):
 
 type
   Task* = object ## `Task` contains the callback and its arguments.
-    callback: proc (args: pointer) {.nimcall, gcsafe.}
+    callback: proc (args, res: pointer) {.nimcall, gcsafe.}
     args: pointer
     destroy: proc (args: pointer) {.nimcall, gcsafe.}
 
 
 proc `=copy`*(x: var Task, y: Task) {.error.}
 
-proc `=destroy`*(t: var Task) {.inline, gcsafe.} =
-  ## Frees the resources allocated for a `Task`.
-  if t.args != nil:
-    if t.destroy != nil:
-      t.destroy(t.args)
-    c_free(t.args)
-
-proc invoke*(task: Task) {.inline, gcsafe.} =
+const arcLike = defined(gcArc) or defined(gcAtomicArc) or defined(gcOrc)
+when defined(nimAllowNonVarDestructor) and arcLike:
+  proc `=destroy`*(t: Task) {.inline, gcsafe.} =
+    ## Frees the resources allocated for a `Task`.
+    if t.args != nil:
+      if t.destroy != nil:
+        t.destroy(t.args)
+      deallocShared(t.args)
+else:
+  proc `=destroy`*(t: var Task) {.inline, gcsafe.} =
+    ## Frees the resources allocated for a `Task`.
+    if t.args != nil:
+      if t.destroy != nil:
+        t.destroy(t.args)
+      deallocShared(t.args)
+
+proc invoke*(task: Task; res: pointer = nil) {.inline, gcsafe.} =
   ## Invokes the `task`.
   assert task.callback != nil
-  task.callback(task.args)
+  task.callback(task.args, res)
 
 template checkIsolate(scratchAssignList: seq[NimNode], procParam, scratchDotExpr: NimNode) =
   # block:
@@ -102,22 +110,38 @@ template addAllNode(assignParam: NimNode, procParam: NimNode) =
   tempAssignList.add newLetStmt(tempNode, newDotExpr(objTemp, formalParams[i][0]))
   scratchRecList.add newIdentDefs(newIdentNode(formalParams[i][0].strVal), assignParam)
 
+proc analyseRootSym(s: NimNode): NimNode =
+  result = s
+  while true:
+    case result.kind
+    of nnkBracketExpr, nnkDerefExpr, nnkHiddenDeref,
+        nnkAddr, nnkHiddenAddr,
+        nnkObjDownConv, nnkObjUpConv:
+      result = result[0]
+    of nnkDotExpr, nnkCheckedFieldExpr, nnkHiddenStdConv, nnkHiddenSubConv:
+      result = result[1]
+    else:
+      break
+
 macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkCallStrLit}): Task =
   ## Converts the call and its arguments to `Task`.
-  runnableExamples("--gc:orc"):
+  runnableExamples:
     proc hello(a: int) = echo a
 
     let b = toTask hello(13)
     assert b is Task
 
-  if getTypeInst(e).typeKind != ntyVoid:
-    error("'toTask' cannot accept a call with a return value", e)
+  let retType = getTypeInst(e)
+  let returnsVoid = retType.typeKind == ntyVoid
+
+  let rootSym = analyseRootSym(e[0])
+  expectKind rootSym, nnkSym
 
   when compileOption("threads"):
-    if not isGcSafe(e[0]):
+    if not isGcSafe(rootSym):
       error("'toTask' takes a GC safe call expression", e)
 
-  if hasClosure(e[0]):
+  if hasClosure(rootSym):
     error("closure call is not allowed", e)
 
   if e.len > 1:
@@ -166,7 +190,7 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC
         # passing by static parameters
         # so we pass them directly instead of passing by scratchObj
         callNode.add nnkExprEqExpr.newTree(formalParams[i][0], e[i])
-      of nnkSym, nnkPtrTy:
+      of nnkSym, nnkPtrTy, nnkProcTy, nnkTupleConstr:
         addAllNode(param, e[i])
       of nnkCharLit..nnkNilLit:
         callNode.add nnkExprEqExpr.newTree(formalParams[i][0], e[i])
@@ -188,40 +212,43 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC
 
 
     let scratchObjPtrType = quote do:
-      cast[ptr `scratchObjType`](c_calloc(csize_t 1, csize_t sizeof(`scratchObjType`)))
-
-    let scratchLetSection = newLetStmt(
-      scratchIdent,
-      scratchObjPtrType
-    )
+      cast[ptr `scratchObjType`](allocShared0(sizeof(`scratchObjType`)))
 
-    let scratchCheck = quote do:
-      if `scratchIdent`.isNil:
-        raise newException(OutOfMemDefect, "Could not allocate memory")
+    let scratchLetSection = newLetStmt(scratchIdent, scratchObjPtrType)
 
     var stmtList = newStmtList()
     stmtList.add(scratchObj)
     stmtList.add(scratchLetSection)
-    stmtList.add(scratchCheck)
     stmtList.add(nnkBlockStmt.newTree(newEmptyNode(), newStmtList(scratchAssignList)))
 
     var functionStmtList = newStmtList()
     let funcCall = newCall(e[0], callNode)
     functionStmtList.add tempAssignList
-    functionStmtList.add funcCall
 
-    let funcName = genSym(nskProc, e[0].strVal)
+    let funcName = genSym(nskProc, rootSym.strVal)
     let destroyName = genSym(nskProc, "destroyScratch")
     let objTemp2 = genSym(ident = "obj")
     let tempNode = quote("@") do:
         `=destroy`(@objTemp2[])
 
+    var funcDecl: NimNode
+    if returnsVoid:
+      funcDecl = quote do:
+        proc `funcName`(args, res: pointer) {.gcsafe, nimcall.} =
+          let `objTemp` = cast[ptr `scratchObjType`](args)
+          `functionStmtList`
+          `funcCall`
+    else:
+      funcDecl = quote do:
+        proc `funcName`(args, res: pointer) {.gcsafe, nimcall.} =
+          let `objTemp` = cast[ptr `scratchObjType`](args)
+          `functionStmtList`
+          cast[ptr `retType`](res)[] = `funcCall`
+
     result = quote do:
       `stmtList`
 
-      proc `funcName`(args: pointer) {.gcsafe, nimcall.} =
-        let `objTemp` = cast[ptr `scratchObjType`](args)
-        `functionStmtList`
+      `funcDecl`
 
       proc `destroyName`(args: pointer) {.gcsafe, nimcall.} =
         let `objTemp2` = cast[ptr `scratchObjType`](args)
@@ -230,18 +257,26 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC
       Task(callback: `funcName`, args: `scratchIdent`, destroy: `destroyName`)
   else:
     let funcCall = newCall(e[0])
-    let funcName = genSym(nskProc, e[0].strVal)
+    let funcName = genSym(nskProc, rootSym.strVal)
 
-    result = quote do:
-      proc `funcName`(args: pointer) {.gcsafe, nimcall.} =
-        `funcCall`
+    if returnsVoid:
+      result = quote do:
+        proc `funcName`(args, res: pointer) {.gcsafe, nimcall.} =
+          `funcCall`
+
+        Task(callback: `funcName`, args: nil)
+    else:
+      result = quote do:
+        proc `funcName`(args, res: pointer) {.gcsafe, nimcall.} =
+          cast[ptr `retType`](res)[] = `funcCall`
+
+        Task(callback: `funcName`, args: nil)
 
-      Task(callback: `funcName`, args: nil)
 
   when defined(nimTasksDebug):
     echo result.repr
 
-runnableExamples("--gc:orc"):
+runnableExamples:
   block:
     var num = 0
     proc hello(a: int) = inc num, a
diff --git a/lib/std/tempfiles.nim b/lib/std/tempfiles.nim
index 1160aaaad..539305bde 100644
--- a/lib/std/tempfiles.nim
+++ b/lib/std/tempfiles.nim
@@ -17,7 +17,7 @@ See also:
 * `mkstemp` (posix), refs https://man7.org/linux/man-pages/man3/mkstemp.3.html
 ]#
 
-import os, random
+import std / [os, random]
 
 when defined(nimPreviewSlimSystem):
   import std/syncio
@@ -29,7 +29,7 @@ const
 
 
 when defined(windows):
-  import winlean
+  import std/winlean
   when defined(nimPreviewSlimSystem):
     import std/widestrs
 
@@ -46,7 +46,7 @@ when defined(windows):
   proc close_osfandle(fd: cint): cint {.
     importc: "_close", header: "<io.h>".}
 else:
-  import posix
+  import std/posix
 
   proc c_fdopen(
     filehandle: cint,
diff --git a/lib/std/time_t.nim b/lib/std/time_t.nim
index 7fb6e6d46..de051b135 100644
--- a/lib/std/time_t.nim
+++ b/lib/std/time_t.nim
@@ -14,10 +14,10 @@ when defined(nimdoc):
       ## Wrapper for `time_t`. On posix, this is an alias to `posix.Time`.
 elif defined(windows):
   when defined(i386) and defined(gcc):
-    type Time* {.importc: "time_t", header: "<time.h>".} = distinct int32
+    type Time* {.importc: "time_t", header: "<time.h>".} = distinct clong
   else:
     # newest version of Visual C++ defines time_t to be of 64 bits
     type Time* {.importc: "time_t", header: "<time.h>".} = distinct int64
 elif defined(posix):
-  import posix
+  import std/posix
   export posix.Time
\ No newline at end of file
diff --git a/lib/std/typedthreads.nim b/lib/std/typedthreads.nim
index 53b18d01e..7b0b81968 100644
--- a/lib/std/typedthreads.nim
+++ b/lib/std/typedthreads.nim
@@ -7,38 +7,74 @@
 #    distribution, for details about the copyright.
 #
 
-## Thread support for Nim.
-##
-## Nim's memory model for threads is quite different from other common
-## programming languages (C, Pascal): Each thread has its own
-## (garbage collected) heap and sharing of memory is restricted. This helps
-## to prevent race conditions and improves efficiency. See `the manual for
-## details of this memory model <manual.html#threads>`_.
-##
-## Examples
-## ========
-##
-## .. code-block:: Nim
-##
-##  import std/locks
-##
-##  var
-##    thr: array[0..4, Thread[tuple[a,b: int]]]
-##    L: Lock
-##
-##  proc threadFunc(interval: tuple[a,b: int]) {.thread.} =
-##    for i in interval.a..interval.b:
-##      acquire(L) # lock stdout
-##      echo i
-##      release(L)
-##
-##  initLock(L)
-##
-##  for i in 0..high(thr):
-##    createThread(thr[i], threadFunc, (i*10, i*10+5))
-##  joinThreads(thr)
-##
-##  deinitLock(L)
+##[
+Thread support for Nim. Threads allow multiple functions to execute concurrently.
+ 
+In Nim, threads are a low-level construct and using a library like `malebolgia`, `taskpools` or `weave` is recommended.
+ 
+When creating a thread, you can pass arguments to it. As Nim's garbage collector does not use atomic references, sharing
+`ref` and other variables managed by the garbage collector between threads is not supported.
+Use global variables to do so, or pointers.
+ 
+Memory allocated using [`sharedAlloc`](./system.html#allocShared.t%2CNatural) can be used and shared between threads.
+
+To communicate between threads, consider using [channels](./system.html#Channel)
+
+Examples
+========
+
+```Nim
+import std/locks
+
+var
+  thr: array[0..4, Thread[tuple[a,b: int]]]
+  L: Lock
+
+proc threadFunc(interval: tuple[a,b: int]) {.thread.} =
+  for i in interval.a..interval.b:
+    acquire(L) # lock stdout
+    echo i
+    release(L)
+
+initLock(L)
+
+for i in 0..high(thr):
+  createThread(thr[i], threadFunc, (i*10, i*10+5))
+joinThreads(thr)
+
+deinitLock(L)
+```
+ 
+When using a memory management strategy that supports shared heaps like `arc` or `boehm`,
+you can pass pointer to threads and share memory between them, but the memory must outlive the thread.
+The default memory management strategy, `orc`, supports this.
+The example below is **not valid** for memory management strategies that use local heaps like `refc`!
+
+```Nim
+import locks
+ 
+var l: Lock
+ 
+proc threadFunc(obj: ptr seq[int]) {.thread.} =
+  withLock l:
+    for i in 0..<100:
+      obj[].add(obj[].len * obj[].len)
+ 
+proc threadHandler() =
+  var thr: array[0..4, Thread[ptr seq[int]]]
+  var s = newSeq[int]()
+    
+  for i in 0..high(thr):
+    createThread(thr[i], threadFunc, s.addr)
+  joinThreads(thr)
+  echo s
+ 
+initLock(l)
+threadHandler()
+deinitLock(l)
+```
+]##
+
 
 import std/private/[threadtypes]
 export Thread
@@ -51,8 +87,11 @@ when defined(nimPreviewSlimSystem):
 when defined(genode):
   import genode/env
 
+when hostOS == "any":
+  {.error: "Threads not implemented for os:any. Please compile with --threads:off.".}
 
-when hasAllocStack or defined(zephyr) or defined(freertos) or defined(cpu16) or defined(cpu8):
+when hasAllocStack or defined(zephyr) or defined(freertos) or defined(nuttx) or
+    defined(cpu16) or defined(cpu8):
   const
     nimThreadStackSize {.intdefine.} = 8192
     nimThreadStackGuard {.intdefine.} = 128
diff --git a/lib/std/varints.nim b/lib/std/varints.nim
index 0d18b9069..32fe2fffb 100644
--- a/lib/std/varints.nim
+++ b/lib/std/varints.nim
@@ -82,29 +82,29 @@ proc writeVu64*(z: var openArray[byte], x: uint64): int =
       z[3] = cast[uint8](y)
       return 4
     z[0] = 251
-    varintWrite32(toOpenArray(z, 1, z.high-1), y)
+    varintWrite32(toOpenArray(z, 1, 4), y)
     return 5
   if w <= 255:
     z[0] = 252
     z[1] = cast[uint8](w)
-    varintWrite32(toOpenArray(z, 2, z.high-2), y)
+    varintWrite32(toOpenArray(z, 2, 5), y)
     return 6
   if w <= 65535:
     z[0] = 253
     z[1] = cast[uint8](w shr 8)
     z[2] = cast[uint8](w)
-    varintWrite32(toOpenArray(z, 3, z.high-3), y)
+    varintWrite32(toOpenArray(z, 3, 6), y)
     return 7
   if w <= 16777215:
     z[0] = 254
     z[1] = cast[uint8](w shr 16)
     z[2] = cast[uint8](w shr 8)
     z[3] = cast[uint8](w)
-    varintWrite32(toOpenArray(z, 4, z.high-4), y)
+    varintWrite32(toOpenArray(z, 4, 7), y)
     return 8
   z[0] = 255
-  varintWrite32(toOpenArray(z, 1, z.high-1), w)
-  varintWrite32(toOpenArray(z, 5, z.high-5), y)
+  varintWrite32(toOpenArray(z, 1, 4), w)
+  varintWrite32(toOpenArray(z, 5, 8), y)
   return 9
 
 proc sar(a, b: int64): int64 =
diff --git a/lib/std/widestrs.nim b/lib/std/widestrs.nim
index 8973579e1..2ddf80d14 100644
--- a/lib/std/widestrs.nim
+++ b/lib/std/widestrs.nim
@@ -25,12 +25,21 @@ when not (defined(cpu16) or defined(cpu8)):
         bytes: int
         data: WideCString
 
-    proc `=destroy`(a: var WideCStringObj) =
-      if a.data != nil:
-        when compileOption("threads"):
-          deallocShared(a.data)
-        else:
-          dealloc(a.data)
+    const arcLike = defined(gcArc) or defined(gcAtomicArc) or defined(gcOrc)
+    when defined(nimAllowNonVarDestructor) and arcLike:
+      proc `=destroy`(a: WideCStringObj) =
+        if a.data != nil:
+          when compileOption("threads"):
+            deallocShared(a.data)
+          else:
+            dealloc(a.data)
+    else:
+      proc `=destroy`(a: var WideCStringObj) =
+        if a.data != nil:
+          when compileOption("threads"):
+            deallocShared(a.data)
+          else:
+            dealloc(a.data)
 
     proc `=copy`(a: var WideCStringObj; b: WideCStringObj) {.error.}
 
@@ -146,6 +155,7 @@ when not (defined(cpu16) or defined(cpu8)):
     createWide(result, size * 2 + 2)
 
   proc newWideCString*(source: cstring, L: int): WideCStringObj =
+    ## Warning:: `source` needs to be preallocated with the length `L`
     createWide(result, L * 2 + 2)
     var d = 0
     for ch in runes(source, L):
diff --git a/lib/std/with.nim b/lib/std/with.nim
index c7338b4e4..c2eaa4bef 100644
--- a/lib/std/with.nim
+++ b/lib/std/with.nim
@@ -14,7 +14,7 @@
 ##
 ## **Since:** version 1.2.
 
-import macros, private / underscored_calls
+import std/[macros, private / underscored_calls]
 
 macro with*(arg: typed; calls: varargs[untyped]): untyped =
   ## This macro provides `chaining`:idx: of function calls.
@@ -35,5 +35,14 @@ macro with*(arg: typed; calls: varargs[untyped]): untyped =
       -= 5
     doAssert a == 43
 
+    # Nesting works for object types too!
+    var foo = (bar: 1, qux: (baz: 2))
+    with foo:
+      bar = 2
+      with qux:
+        baz = 3
+    doAssert foo.bar == 2
+    doAssert foo.qux.baz == 3
+
   result = newNimNode(nnkStmtList, arg)
   underscoredCalls(result, calls, arg)
diff --git a/lib/std/wordwrap.nim b/lib/std/wordwrap.nim
index 7dcfc7f59..9333f880b 100644
--- a/lib/std/wordwrap.nim
+++ b/lib/std/wordwrap.nim
@@ -9,7 +9,7 @@
 
 ## This module contains an algorithm to wordwrap a Unicode string.
 
-import strutils, unicode
+import std/[strutils, unicode]
 
 proc olen(s: string; start, lastExclusive: int): int =
   var i = start
diff --git a/lib/std/wrapnils.nim b/lib/std/wrapnils.nim
index 235638134..0b75c270e 100644
--- a/lib/std/wrapnils.nim
+++ b/lib/std/wrapnils.nim
@@ -13,7 +13,7 @@ consider handling indexing operations, eg:
 doAssert ?.default(seq[int])[3] == default(int)
 ]#
 
-import macros
+import std/macros
 
 runnableExamples:
   type Foo = ref object
@@ -122,7 +122,7 @@ macro `?.`*(a: typed): auto =
     `lhs`
 
 # the code below is not needed for `?.`
-from options import Option, isSome, get, option, unsafeGet, UnpackDefect
+from std/options import Option, isSome, get, option, unsafeGet, UnpackDefect
 
 macro `??.`*(a: typed): Option =
   ## Same as `?.` but returns an `Option`.