summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/deprecated/pure/actors.nim3
-rw-r--r--lib/impure/db_mysql.nim35
-rw-r--r--lib/impure/db_postgres.nim7
-rw-r--r--lib/impure/db_sqlite.nim1
-rw-r--r--lib/impure/nre.nim12
-rw-r--r--lib/impure/nre/private/util.nim6
-rw-r--r--lib/impure/re.nim10
-rw-r--r--lib/packages/docutils/rstast.nim4
-rw-r--r--lib/packages/docutils/rstgen.nim16
-rw-r--r--lib/pure/asyncfutures.nim4
-rw-r--r--lib/pure/asyncnet.nim6
-rw-r--r--lib/pure/collections/intsets.nim24
-rw-r--r--lib/pure/collections/tables.nim2
-rw-r--r--lib/pure/concurrency/threadpool.nim54
-rw-r--r--lib/pure/htmlparser.nim1
-rw-r--r--lib/pure/httpclient.nim16
-rw-r--r--lib/pure/json.nim2
-rw-r--r--lib/pure/net.nim48
-rw-r--r--lib/pure/parseopt2.nim6
-rw-r--r--lib/pure/parsexml.nim10
-rw-r--r--lib/pure/pegs.nim4
-rw-r--r--lib/pure/ropes.nim69
-rw-r--r--lib/pure/smtp.nim6
-rw-r--r--lib/pure/streams.nim5
-rw-r--r--lib/pure/strutils.nim13
-rw-r--r--lib/pure/unittest.nim17
-rw-r--r--lib/pure/xmldom.nim24
-rw-r--r--lib/pure/xmldomparser.nim4
-rw-r--r--lib/system.nim146
-rw-r--r--lib/system/jssys.nim2
-rw-r--r--lib/system/sysstr.nim2
31 files changed, 223 insertions, 336 deletions
diff --git a/lib/deprecated/pure/actors.nim b/lib/deprecated/pure/actors.nim
index 17321cc0e..451668825 100644
--- a/lib/deprecated/pure/actors.nim
+++ b/lib/deprecated/pure/actors.nim
@@ -43,7 +43,6 @@ type
     t: Thread[ptr Actor[In, Out]]
 
   PActor*[In, Out] = ptr Actor[In, Out] ## an actor
-{.deprecated: [TTask: Task, TActor: Actor].}
 
 proc spawn*[In, Out](action: proc(
     self: PActor[In, Out]){.thread.}): PActor[In, Out] =
@@ -168,7 +167,7 @@ proc terminate*[In, Out](a: var ActorPool[In, Out]) =
   for i in 0..<a.actors.len: join(a.actors[i])
   when Out isnot void:
     close(a.outputs)
-  a.actors = nil
+  a.actors = @[]
 
 proc join*[In, Out](a: var ActorPool[In, Out]) =
   ## short-cut for `sync` and then `terminate`.
diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim
index ca0e29d11..26bc7d0ad 100644
--- a/lib/impure/db_mysql.nim
+++ b/lib/impure/db_mysql.nim
@@ -128,10 +128,7 @@ proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string =
   var a = 0
   for c in items(string(formatstr)):
     if c == '?':
-      if args[a].isNil:
-        add(result, "NULL")
-      else:
-        add(result, dbQuote(args[a]))
+      add(result, dbQuote(args[a]))
       inc(a)
     else:
       add(result, c)
@@ -183,24 +180,8 @@ iterator fastRows*(db: DbConn, query: SqlQuery,
       row = mysql.fetchRow(sqlres)
       if row == nil: break
       for i in 0..L-1:
-        if row[i] == nil:
-          if backup == nil:
-            newSeq(backup, L)
-          if backup[i] == nil and result[i] != nil:
-            shallowCopy(backup[i], result[i])
-          result[i] = nil
-        else:
-          if result[i] == nil:
-            if backup != nil:
-              if backup[i] == nil:
-                backup[i] = ""
-              shallowCopy(result[i], backup[i])
-              setLen(result[i], 0)
-            else:
-              result[i] = ""
-          else:
-            setLen(result[i], 0)
-          add(result[i], row[i])
+        setLen(result[i], 0)
+        result[i].add row[i]
       yield result
     properFreeResult(sqlres, row)
 
@@ -323,10 +304,7 @@ proc getRow*(db: DbConn, query: SqlQuery,
     if row != nil:
       for i in 0..L-1:
         setLen(result[i], 0)
-        if row[i] == nil:
-          result[i] = nil
-        else:
-          add(result[i], row[i])
+        add(result[i], row[i])
     properFreeResult(sqlres, row)
 
 proc getAllRows*(db: DbConn, query: SqlQuery,
@@ -345,10 +323,7 @@ proc getAllRows*(db: DbConn, query: SqlQuery,
       setLen(result, j+1)
       newSeq(result[j], L)
       for i in 0..L-1:
-        if row[i] == nil:
-          result[j][i] = nil
-        else:
-          result[j][i] = $row[i]
+        result[j][i] = $row[i]
       inc(j)
     mysql.freeResult(sqlres)
 
diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim
index 1459f0d7e..e765cc197 100644
--- a/lib/impure/db_postgres.nim
+++ b/lib/impure/db_postgres.nim
@@ -103,10 +103,7 @@ proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string =
   else:
     for c in items(string(formatstr)):
       if c == '?':
-        if args[a] == nil:
-          add(result, "NULL")
-        else:
-          add(result, dbQuote(args[a]))
+        add(result, dbQuote(args[a]))
         inc(a)
       else:
         add(result, c)
@@ -179,7 +176,7 @@ proc setRow(res: PPGresult, r: var Row, line, cols: int32) =
     setLen(r[col], 0)
     let x = pqgetvalue(res, line, col)
     if x.isNil:
-      r[col] = nil
+      r[col] = ""
     else:
       add(r[col], x)
 
diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim
index fd25b2b94..a40c88a11 100644
--- a/lib/impure/db_sqlite.nim
+++ b/lib/impure/db_sqlite.nim
@@ -105,7 +105,6 @@ proc dbError*(db: DbConn) {.noreturn.} =
 
 proc dbQuote*(s: string): string =
   ## DB quotes the string.
-  if s.isNil: return "NULL"
   result = "'"
   for c in items(s):
     if c == '\'': add(result, "''")
diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim
index 889210f62..32b1d0255 100644
--- a/lib/impure/nre.nim
+++ b/lib/impure/nre.nim
@@ -267,7 +267,7 @@ proc `[]`*(pattern: Captures, i: int): string =
     let bounds = bounds.get
     return pattern.str.substr(bounds.a, bounds.b)
   else:
-    return nil
+    return ""
 
 proc match*(pattern: RegexMatch): string =
   return pattern.captures[-1]
@@ -291,9 +291,9 @@ template toTableImpl(cond: untyped) {.dirty.} =
     else:
       result[key] = nextVal
 
-proc toTable*(pattern: Captures, default: string = nil): Table[string, string] =
+proc toTable*(pattern: Captures, default: string = ""): Table[string, string] =
   result = initTable[string, string]()
-  toTableImpl(nextVal == nil)
+  toTableImpl(nextVal.len == 0)
 
 proc toTable*(pattern: CaptureBounds, default = none(HSlice[int, int])):
     Table[string, Option[HSlice[int, int]]] =
@@ -312,13 +312,13 @@ template itemsImpl(cond: untyped) {.dirty.} =
 iterator items*(pattern: CaptureBounds, default = none(HSlice[int, int])): Option[HSlice[int, int]] =
   itemsImpl(nextVal.isNone)
 
-iterator items*(pattern: Captures, default: string = nil): string =
-  itemsImpl(nextVal == nil)
+iterator items*(pattern: Captures, default: string = ""): string =
+  itemsImpl(nextVal.len == 0)
 
 proc toSeq*(pattern: CaptureBounds, default = none(HSlice[int, int])): seq[Option[HSlice[int, int]]] =
   accumulateResult(pattern.items(default))
 
-proc toSeq*(pattern: Captures, default: string = nil): seq[string] =
+proc toSeq*(pattern: Captures, default: string = ""): seq[string] =
   accumulateResult(pattern.items(default))
 
 proc `$`*(pattern: RegexMatch): string =
diff --git a/lib/impure/nre/private/util.nim b/lib/impure/nre/private/util.nim
index 12d2506ea..a3ae84007 100644
--- a/lib/impure/nre/private/util.nim
+++ b/lib/impure/nre/private/util.nim
@@ -10,11 +10,7 @@ proc fget*[K, V](self: Table[K, V], key: K): V =
 const Ident = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'}
 const StartIdent = Ident - {'0'..'9'}
 
-proc checkNil(arg: string): string =
-  if arg == nil:
-    raise newException(ValueError, "Cannot use nil capture")
-  else:
-    return arg
+template checkNil(arg: string): string = arg
 
 template formatStr*(howExpr, namegetter, idgetter): untyped =
   let how = howExpr
diff --git a/lib/impure/re.nim b/lib/impure/re.nim
index 201c490f3..a60f70828 100644
--- a/lib/impure/re.nim
+++ b/lib/impure/re.nim
@@ -113,7 +113,7 @@ proc matchOrFind(buf: cstring, pattern: Regex, matches: var openArray[string],
     var b = rawMatches[i * 2 + 1]
     if a >= 0'i32:
       matches[i-1] = bufSubstr(buf, int(a), int(b))
-    else: matches[i-1] = nil
+    else: matches[i-1] = ""
   return rawMatches[1] - rawMatches[0]
 
 proc findBounds*(buf: cstring, pattern: Regex, matches: var openArray[string],
@@ -133,7 +133,7 @@ proc findBounds*(buf: cstring, pattern: Regex, matches: var openArray[string],
     var a = rawMatches[i * 2]
     var b = rawMatches[i * 2 + 1]
     if a >= 0'i32: matches[i-1] = bufSubstr(buf, int(a), int(b))
-    else: matches[i-1] = nil
+    else: matches[i-1] = ""
   return (rawMatches[0].int, rawMatches[1].int - 1)
 
 proc findBounds*(s: string, pattern: Regex, matches: var openArray[string],
@@ -287,7 +287,7 @@ proc find*(buf: cstring, pattern: Regex, matches: var openArray[string],
     var a = rawMatches[i * 2]
     var b = rawMatches[i * 2 + 1]
     if a >= 0'i32: matches[i-1] = bufSubstr(buf, int(a), int(b))
-    else: matches[i-1] = nil
+    else: matches[i-1] = ""
   return rawMatches[0]
 
 proc find*(s: string, pattern: Regex, matches: var openArray[string],
@@ -456,8 +456,6 @@ proc replacef*(s: string, sub: Regex, by: string): string =
   while true:
     var match = findBounds(s, sub, caps, prev)
     if match.first < 0: break
-    assert result != nil
-    assert s != nil
     add(result, substr(s, prev, match.first-1))
     addf(result, by, caps)
     prev = match.last + 1
@@ -615,7 +613,7 @@ when isMainModule:
     doAssert false
 
   if "abc" =~ re"(cba)?.*":
-    doAssert matches[0] == nil
+    doAssert matches[0] == ""
   else: doAssert false
 
   if "abc" =~ re"().*":
diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim
index f3596b571..4a77b4f34 100644
--- a/lib/packages/docutils/rstast.nim
+++ b/lib/packages/docutils/rstast.nim
@@ -293,9 +293,9 @@ proc renderRstToJsonNode(node: PRstNode): JsonNode =
       (key: "kind", val: %($node.kind)),
       (key: "level", val: %BiggestInt(node.level))
      ]
-  if node.text != nil:
+  if node.text.len > 0:
     result.add("text", %node.text)
-  if node.sons != nil and len(node.sons) > 0:
+  if len(node.sons) > 0:
     var accm = newSeq[JsonNode](len(node.sons))
     for i, son in node.sons:
       accm[i] = renderRstToJsonNode(son)
diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim
index 43a429a17..5b0b6c6ee 100644
--- a/lib/packages/docutils/rstgen.nim
+++ b/lib/packages/docutils/rstgen.nim
@@ -312,7 +312,6 @@ proc setIndexTerm*(d: var RstGenerator, id, term: string,
   ## The index won't be written to disk unless you call `writeIndexFile()
   ## <#writeIndexFile>`_. The purpose of the index is documented in the `docgen
   ## tools guide <docgen.html#index-switch>`_.
-  assert(not d.theIndex.isNil)
   var
     entry = term
     isTitle = false
@@ -337,7 +336,7 @@ proc hash(n: PRstNode): int =
     result = hash(n.text)
   elif n.len > 0:
     result = hash(n.sons[0])
-    for i in 1 .. <len(n):
+    for i in 1 ..< len(n):
       result = result !& hash(n.sons[i])
     result = !$result
 
@@ -398,9 +397,9 @@ proc hash(x: IndexEntry): Hash =
 proc `<-`(a: var IndexEntry, b: IndexEntry) =
   shallowCopy a.keyword, b.keyword
   shallowCopy a.link, b.link
-  if b.linkTitle.isNil: a.linkTitle = nil
+  if b.linkTitle.isNil: a.linkTitle = ""
   else: shallowCopy a.linkTitle, b.linkTitle
-  if b.linkDesc.isNil: a.linkDesc = nil
+  if b.linkDesc.isNil: a.linkDesc = ""
   else: shallowCopy a.linkDesc, b.linkDesc
 
 proc sortIndex(a: var openArray[IndexEntry]) =
@@ -452,7 +451,7 @@ proc generateSymbolIndex(symbols: seq[IndexEntry]): string =
           title="$3" data-doc-search-tag="$2" href="$1">$2</a></li>
           """, [url, text, desc])
       else:
-        result.addf("""<li><a class="reference external" 
+        result.addf("""<li><a class="reference external"
           data-doc-search-tag="$2" href="$1">$2</a></li>
           """, [url, text])
       inc j
@@ -524,7 +523,7 @@ proc generateDocumentationTOC(entries: seq[IndexEntry]): string =
       titleTag = levels[L].text
     else:
       result.add(level.indentToLevel(levels[L].level))
-      result.addf("""<li><a class="reference" data-doc-search-tag="$1" href="$2"> 
+      result.addf("""<li><a class="reference" data-doc-search-tag="$1" href="$2">
         $3</a></li>
         """, [titleTag & " : " & levels[L].text, link, levels[L].text])
     inc L
@@ -608,8 +607,8 @@ proc readIndexDir(dir: string):
           fileEntries[F].linkTitle = extraCols[1].unquoteIndexColumn
           fileEntries[F].linkDesc = extraCols[2].unquoteIndexColumn
         else:
-          fileEntries[F].linkTitle = nil
-          fileEntries[F].linkDesc = nil
+          fileEntries[F].linkTitle = ""
+          fileEntries[F].linkDesc = ""
         inc F
       # Depending on type add this to the list of symbols or table of APIs.
       if title.keyword.isNil:
@@ -657,7 +656,6 @@ proc mergeIndexes*(dir: string): string =
   ## Returns the merged and sorted indices into a single HTML block which can
   ## be further embedded into nimdoc templates.
   var (modules, symbols, docs) = readIndexDir(dir)
-  assert(not symbols.isNil)
 
   result = ""
   # Generate a quick jump list of documents.
diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim
index 863a6843b..5bf9183ed 100644
--- a/lib/pure/asyncfutures.nim
+++ b/lib/pure/asyncfutures.nim
@@ -219,10 +219,10 @@ proc getHint(entry: StackTraceEntry): string =
   ## We try to provide some hints about stack trace entries that the user
   ## may not be familiar with, in particular calls inside the stdlib.
   result = ""
-  if entry.procname == "processPendingCallbacks":
+  if entry.procname == cstring"processPendingCallbacks":
     if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0:
       return "Executes pending callbacks"
-  elif entry.procname == "poll":
+  elif entry.procname == cstring"poll":
     if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0:
       return "Processes asynchronous completion events"
 
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index e7552e3e3..71a1600dc 100644
--- a/lib/pure/asyncnet.nim
+++ b/lib/pure/asyncnet.nim
@@ -493,8 +493,6 @@ proc recvLineInto*(socket: AsyncSocket, resString: FutureVar[string],
   ## **Warning**: ``recvLineInto`` on unbuffered sockets assumes that the
   ## protocol uses ``\r\L`` to delimit a new line.
   assert SocketFlag.Peek notin flags ## TODO:
-  assert(not resString.mget.isNil(),
-         "String inside resString future needs to be initialised")
   result = newFuture[void]("asyncnet.recvLineInto")
 
   # TODO: Make the async transformation check for FutureVar params and complete
@@ -657,7 +655,7 @@ when defineSsl:
 
   proc wrapConnectedSocket*(ctx: SslContext, socket: AsyncSocket,
                             handshake: SslHandshakeType,
-                            hostname: string = nil) =
+                            hostname: string = "") =
     ## Wraps a connected socket in an SSL context. This function effectively
     ## turns ``socket`` into an SSL socket.
     ## ``hostname`` should be specified so that the client knows which hostname
@@ -672,7 +670,7 @@ when defineSsl:
 
     case handshake
     of handshakeAsClient:
-      if not hostname.isNil and not isIpAddress(hostname):
+      if hostname.len > 0 and not isIpAddress(hostname):
         # Set the SNI address for this connection. This call can fail if
         # we're not using TLSv1+.
         discard SSL_set_tlsext_host_name(socket.sslHandle, hostname)
diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim
index bfecfe447..545958977 100644
--- a/lib/pure/collections/intsets.nim
+++ b/lib/pure/collections/intsets.nim
@@ -184,7 +184,7 @@ proc missingOrExcl*(s: var IntSet, key: int) : bool =
   ## `key` is removed from `s` and false is returned.
   var count = s.elems
   exclImpl(s, key)
-  result = count == s.elems 
+  result = count == s.elems
 
 proc containsOrIncl*(s: var IntSet, key: int): bool =
   ## returns true if `s` contains `key`, otherwise `key` is included in `s`
@@ -212,7 +212,10 @@ proc initIntSet*: IntSet =
 
   #newSeq(result.data, InitIntSetSize)
   #result.max = InitIntSetSize-1
-  result.data = nil
+  when defined(nimNoNilSeqs):
+    result.data = @[]
+  else:
+    result.data = nil
   result.max = 0
   result.counter = 0
   result.head = nil
@@ -222,7 +225,10 @@ proc clear*(result: var IntSet) =
   #setLen(result.data, InitIntSetSize)
   #for i in 0..InitIntSetSize-1: result.data[i] = nil
   #result.max = InitIntSetSize-1
-  result.data = nil
+  when defined(nimNoNilSeqs):
+    result.data = @[]
+  else:
+    result.data = nil
   result.max = 0
   result.counter = 0
   result.head = nil
@@ -234,7 +240,10 @@ proc assign*(dest: var IntSet, src: IntSet) =
   ## copies `src` to `dest`. `dest` does not need to be initialized by
   ## `initIntSet`.
   if src.elems <= src.a.len:
-    dest.data = nil
+    when defined(nimNoNilSeqs):
+      dest.data = @[]
+    else:
+      dest.data = nil
     dest.max = 0
     dest.counter = src.counter
     dest.head = nil
@@ -247,11 +256,9 @@ proc assign*(dest: var IntSet, src: IntSet) =
 
     var it = src.head
     while it != nil:
-
       var h = it.key and dest.max
       while dest.data[h] != nil: h = nextTry(h, dest.max)
       assert(dest.data[h] == nil)
-
       var n: PTrunk
       new(n)
       n.next = dest.head
@@ -259,7 +266,6 @@ proc assign*(dest: var IntSet, src: IntSet) =
       n.bits = it.bits
       dest.head = n
       dest.data[h] = n
-
       it = it.next
 
 proc union*(s1, s2: IntSet): IntSet =
@@ -315,7 +321,7 @@ proc len*(s: IntSet): int {.inline.} =
     for _ in s:
       inc(result)
 
-proc card*(s: IntSet): int {.inline.} = 
+proc card*(s: IntSet): int {.inline.} =
   ## alias for `len() <#len>` _.
   result = s.len()
 
@@ -361,7 +367,7 @@ when isMainModule:
   x.incl(1056)
 
   x.incl(1044)
-  x.excl(1044) 
+  x.excl(1044)
 
   assert x.containsOrIncl(888) == false
   assert 888 in x
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index 308f31eae..f85de7546 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -1329,7 +1329,7 @@ when isMainModule:
     doAssert clearTable[42] == "asd"
     clearTable.clear()
     doAssert(not clearTable.hasKey(123123))
-    doAssert clearTable.getOrDefault(42) == nil
+    doAssert clearTable.getOrDefault(42) == ""
 
   block: #5482
     var a = [("wrong?","foo"), ("wrong?", "foo2")].newOrderedTable()
diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim
index 6ec71e912..f3b13fac5 100644
--- a/lib/pure/concurrency/threadpool.nim
+++ b/lib/pure/concurrency/threadpool.nim
@@ -30,7 +30,7 @@ proc destroySemaphore(cv: var Semaphore) {.inline.} =
   deinitCond(cv.c)
   deinitLock(cv.L)
 
-proc await(cv: var Semaphore) =
+proc blockUntil(cv: var Semaphore) =
   acquire(cv.L)
   while cv.counter <= 0:
     wait(cv.c, cv.L)
@@ -81,7 +81,7 @@ proc closeBarrier(b: ptr Barrier) {.compilerProc.} =
     fence()
     b.interest = true
     fence()
-    while b.left != b.entered: await(b.cv)
+    while b.left != b.entered: blockUntil(b.cv)
     destroySemaphore(b.cv)
 
 {.pop.}
@@ -89,8 +89,6 @@ proc closeBarrier(b: ptr Barrier) {.compilerProc.} =
 # ----------------------------------------------------------------------------
 
 type
-  foreign* = object ## a region that indicates the pointer comes from a
-                    ## foreign thread heap.
   AwaitInfo = object
     cv: Semaphore
     idx: int
@@ -99,7 +97,7 @@ type
   FlowVarBaseObj = object of RootObj
     ready, usesSemaphore, awaited: bool
     cv: Semaphore #\
-    # for 'awaitAny' support
+    # for 'blockUntilAny' support
     ai: ptr AwaitInfo
     idx: int
     data: pointer  # we incRef and unref it to keep it alive; note this MUST NOT
@@ -130,12 +128,12 @@ type
     q: ToFreeQueue
     readyForTask: Semaphore
 
-proc await*(fv: FlowVarBase) =
+proc blockUntil*(fv: FlowVarBase) =
   ## waits until the value for the flowVar arrives. Usually it is not necessary
   ## to call this explicitly.
   if fv.usesSemaphore and not fv.awaited:
     fv.awaited = true
-    await(fv.cv)
+    blockUntil(fv.cv)
     destroySemaphore(fv.cv)
 
 proc selectWorker(w: ptr Worker; fn: WorkerProc; data: pointer): bool =
@@ -143,7 +141,7 @@ proc selectWorker(w: ptr Worker; fn: WorkerProc; data: pointer): bool =
     w.data = data
     w.f = fn
     signal(w.taskArrived)
-    await(w.taskStarted)
+    blockUntil(w.taskStarted)
     result = true
 
 proc cleanFlowVars(w: ptr Worker) =
@@ -178,11 +176,11 @@ proc attach(fv: FlowVarBase; i: int): bool =
   release(fv.cv.L)
 
 proc finished(fv: FlowVarBase) =
-  doAssert fv.ai.isNil, "flowVar is still attached to an 'awaitAny'"
+  doAssert fv.ai.isNil, "flowVar is still attached to an 'blockUntilAny'"
   # we have to protect against the rare cases where the owner of the flowVar
   # simply disregards the flowVar and yet the "flowVar" has not yet written
   # anything to it:
-  await(fv)
+  blockUntil(fv)
   if fv.data.isNil: return
   let owner = cast[ptr Worker](fv.owner)
   let q = addr(owner.q)
@@ -191,7 +189,7 @@ proc finished(fv: FlowVarBase) =
     #echo "EXHAUSTED!"
     release(q.lock)
     wakeupWorkerToProcessQueue(owner)
-    await(q.empty)
+    blockUntil(q.empty)
     acquire(q.lock)
   q.data[q.len] = cast[pointer](fv.data)
   inc q.len
@@ -222,7 +220,7 @@ proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) =
   ## to ``action``. Note that due to Nim's parameter passing semantics this
   ## means that ``T`` doesn't need to be copied and so ``awaitAndThen`` can
   ## sometimes be more efficient than ``^``.
-  await(fv)
+  blockUntil(fv)
   when T is string or T is seq:
     action(cast[T](fv.data))
   elif T is ref:
@@ -231,31 +229,31 @@ proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) =
     action(fv.blob)
   finished(fv)
 
-proc unsafeRead*[T](fv: FlowVar[ref T]): foreign ptr T =
+proc unsafeRead*[T](fv: FlowVar[ref T]): ptr T =
   ## blocks until the value is available and then returns this value.
-  await(fv)
-  result = cast[foreign ptr T](fv.data)
+  blockUntil(fv)
+  result = cast[ptr T](fv.data)
 
 proc `^`*[T](fv: FlowVar[ref T]): ref T =
   ## blocks until the value is available and then returns this value.
-  await(fv)
+  blockUntil(fv)
   let src = cast[ref T](fv.data)
   deepCopy result, src
 
 proc `^`*[T](fv: FlowVar[T]): T =
   ## blocks until the value is available and then returns this value.
-  await(fv)
+  blockUntil(fv)
   when T is string or T is seq:
     # XXX closures? deepCopy?
     result = cast[T](fv.data)
   else:
     result = fv.blob
 
-proc awaitAny*(flowVars: openArray[FlowVarBase]): int =
+proc blockUntilAny*(flowVars: openArray[FlowVarBase]): int =
   ## awaits any of the given flowVars. Returns the index of one flowVar for
-  ## which a value arrived. A flowVar only supports one call to 'awaitAny' at
-  ## the same time. That means if you awaitAny([a,b]) and awaitAny([b,c]) the second
-  ## call will only await 'c'. If there is no flowVar left to be able to wait
+  ## which a value arrived. A flowVar only supports one call to 'blockUntilAny' at
+  ## the same time. That means if you blockUntilAny([a,b]) and blockUntilAny([b,c]) the second
+  ## call will only blockUntil 'c'. If there is no flowVar left to be able to wait
   ## on, -1 is returned.
   ## **Note**: This results in non-deterministic behaviour and should be avoided.
   var ai: AwaitInfo
@@ -271,7 +269,7 @@ proc awaitAny*(flowVars: openArray[FlowVarBase]): int =
       inc conflicts
   if conflicts < flowVars.len:
     if result < 0:
-      await(ai.cv)
+      blockUntil(ai.cv)
       result = ai.idx
     for i in 0 .. flowVars.high:
       discard cas(addr flowVars[i].ai, addr ai, nil)
@@ -328,7 +326,7 @@ proc slave(w: ptr Worker) {.thread.} =
       w.ready = true
     readyWorker = w
     signal(gSomeReady)
-    await(w.taskArrived)
+    blockUntil(w.taskArrived)
     # XXX Somebody needs to look into this (why does this assertion fail
     # in Visual Studio?)
     when not defined(vcc) and not defined(tcc): assert(not w.ready)
@@ -353,7 +351,7 @@ proc distinguishedSlave(w: ptr Worker) {.thread.} =
     else:
       w.ready = true
     signal(w.readyForTask)
-    await(w.taskArrived)
+    blockUntil(w.taskArrived)
     assert(not w.ready)
     w.f(w, w.data)
     if w.q.len != 0: w.cleanFlowVars
@@ -501,7 +499,7 @@ proc nimSpawn3(fn: WorkerProc; data: pointer) {.compilerProc.} =
         # on the current thread instead.
         var self = addr(workersData[localThreadId-1])
         fn(self, data)
-        await(self.taskStarted)
+        blockUntil(self.taskStarted)
         return
 
     if isSlave:
@@ -526,7 +524,7 @@ proc nimSpawn3(fn: WorkerProc; data: pointer) {.compilerProc.} =
 
         inc numSlavesWaiting
 
-    await(gSomeReady)
+    blockUntil(gSomeReady)
 
     if isSlave:
       withLock numSlavesLock:
@@ -544,7 +542,7 @@ proc nimSpawn4(fn: WorkerProc; data: pointer; id: ThreadId) {.compilerProc.} =
   release(distinguishedLock)
   while true:
     if selectWorker(addr(distinguishedData[id]), fn, data): break
-    await(distinguishedData[id].readyForTask)
+    blockUntil(distinguishedData[id].readyForTask)
 
 
 proc sync*() =
@@ -557,7 +555,7 @@ proc sync*() =
       if not allReady: break
       allReady = allReady and workersData[i].ready
     if allReady: break
-    await(gSomeReady)
+    blockUntil(gSomeReady)
     inc toRelease
 
   for i in 0 ..< toRelease:
diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim
index c38c36874..f54fe87f7 100644
--- a/lib/pure/htmlparser.nim
+++ b/lib/pure/htmlparser.nim
@@ -1869,7 +1869,6 @@ proc entityToUtf8*(entity: string): string =
   ## "" is returned if the entity name is unknown. The HTML parser
   ## already converts entities to UTF-8.
   runnableExamples:
-    doAssert entityToUtf8(nil) == ""
     doAssert entityToUtf8("") == ""
     doAssert entityToUtf8("a") == ""
     doAssert entityToUtf8("gt") == ">"
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 72de72718..0192e71e7 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -378,23 +378,23 @@ proc newMultipartData*: MultipartData =
   ## Constructs a new ``MultipartData`` object.
   MultipartData(content: @[])
 
-proc add*(p: var MultipartData, name, content: string, filename: string = nil,
-          contentType: string = nil) =
+proc add*(p: var MultipartData, name, content: string, filename: string = "",
+          contentType: string = "") =
   ## Add a value to the multipart data. Raises a `ValueError` exception if
   ## `name`, `filename` or `contentType` contain newline characters.
 
   if {'\c','\L'} in name:
     raise newException(ValueError, "name contains a newline character")
-  if filename != nil and {'\c','\L'} in filename:
+  if {'\c','\L'} in filename:
     raise newException(ValueError, "filename contains a newline character")
-  if contentType != nil and {'\c','\L'} in contentType:
+  if {'\c','\L'} in contentType:
     raise newException(ValueError, "contentType contains a newline character")
 
   var str = "Content-Disposition: form-data; name=\"" & name & "\""
-  if filename != nil:
+  if filename.len > 0:
     str.add("; filename=\"" & filename & "\"")
   str.add("\c\L")
-  if contentType != nil:
+  if contentType.len > 0:
     str.add("Content-Type: " & contentType & "\c\L")
   str.add("\c\L" & content & "\c\L")
 
@@ -434,7 +434,7 @@ proc addFiles*(p: var MultipartData, xs: openarray[tuple[name, file: string]]):
     var contentType: string
     let (_, fName, ext) = splitFile(file)
     if ext.len > 0:
-      contentType = m.getMimetype(ext[1..ext.high], nil)
+      contentType = m.getMimetype(ext[1..ext.high], "")
     p.add(name, readFile(file), fName & ext, contentType)
   result = p
 
@@ -457,7 +457,7 @@ proc `[]=`*(p: var MultipartData, name: string,
   p.add(name, file.content, file.name, file.contentType)
 
 proc format(p: MultipartData): tuple[contentType, body: string] =
-  if p == nil or p.content == nil or p.content.len == 0:
+  if p == nil or p.content.len == 0:
     return ("", "")
 
   # Create boundary that is not in the data to be formatted
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index b9279b18c..69ffb1796 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -1144,7 +1144,7 @@ proc processType(typeName: NimNode, obj: NimNode,
       result = quote do:
         (
           verifyJsonKind(`jsonNode`, {JString, JNull}, astToStr(`jsonNode`));
-          if `jsonNode`.kind == JNull: nil else: `jsonNode`.str
+          if `jsonNode`.kind == JNull: "" else: `jsonNode`.str
         )
     of "biggestint":
       result = quote do:
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index 771e7de10..0e56100d9 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -231,7 +231,7 @@ proc newSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM,
     raiseOSError(osLastError())
   result = newSocket(fd, domain, sockType, protocol, buffered)
 
-proc parseIPv4Address(address_str: string): IpAddress =
+proc parseIPv4Address(addressStr: string): IpAddress =
   ## Parses IPv4 adresses
   ## Raises EInvalidValue on errors
   var
@@ -241,15 +241,15 @@ proc parseIPv4Address(address_str: string): IpAddress =
 
   result.family = IpAddressFamily.IPv4
 
-  for i in 0 .. high(address_str):
-    if address_str[i] in strutils.Digits: # Character is a number
+  for i in 0 .. high(addressStr):
+    if addressStr[i] in strutils.Digits: # Character is a number
       currentByte = currentByte * 10 +
-        cast[uint16](ord(address_str[i]) - ord('0'))
+        cast[uint16](ord(addressStr[i]) - ord('0'))
       if currentByte > 255'u16:
         raise newException(ValueError,
           "Invalid IP Address. Value is out of range")
       seperatorValid = true
-    elif address_str[i] == '.': # IPv4 address separator
+    elif addressStr[i] == '.': # IPv4 address separator
       if not seperatorValid or byteCount >= 3:
         raise newException(ValueError,
           "Invalid IP Address. The address consists of too many groups")
@@ -265,11 +265,11 @@ proc parseIPv4Address(address_str: string): IpAddress =
     raise newException(ValueError, "Invalid IP Address")
   result.address_v4[byteCount] = cast[uint8](currentByte)
 
-proc parseIPv6Address(address_str: string): IpAddress =
+proc parseIPv6Address(addressStr: string): IpAddress =
   ## Parses IPv6 adresses
   ## Raises EInvalidValue on errors
   result.family = IpAddressFamily.IPv6
-  if address_str.len < 2:
+  if addressStr.len < 2:
     raise newException(ValueError, "Invalid IP Address")
 
   var
@@ -282,7 +282,7 @@ proc parseIPv6Address(address_str: string): IpAddress =
     v4StartPos = -1
     byteCount = 0
 
-  for i,c in address_str:
+  for i,c in addressStr:
     if c == ':':
       if not seperatorValid:
         raise newException(ValueError,
@@ -293,7 +293,7 @@ proc parseIPv6Address(address_str: string): IpAddress =
             "Invalid IP Address. Address contains more than one \"::\" seperator")
         dualColonGroup = groupCount
         seperatorValid = false
-      elif i != 0 and i != high(address_str):
+      elif i != 0 and i != high(addressStr):
         if groupCount >= 8:
           raise newException(ValueError,
             "Invalid IP Address. The address consists of too many groups")
@@ -303,11 +303,11 @@ proc parseIPv6Address(address_str: string): IpAddress =
         groupCount.inc()
         if dualColonGroup != -1: seperatorValid = false
       elif i == 0: # only valid if address starts with ::
-        if address_str[1] != ':':
+        if addressStr[1] != ':':
           raise newException(ValueError,
             "Invalid IP Address. Address may not start with \":\"")
-      else: # i == high(address_str) - only valid if address ends with ::
-        if address_str[high(address_str)-1] != ':':
+      else: # i == high(addressStr) - only valid if address ends with ::
+        if addressStr[high(addressStr)-1] != ':':
           raise newException(ValueError,
             "Invalid IP Address. Address may not end with \":\"")
       lastWasColon = true
@@ -345,7 +345,7 @@ proc parseIPv6Address(address_str: string): IpAddress =
       result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF)
       groupCount.inc()
   else: # Must parse IPv4 address
-    for i,c in address_str[v4StartPos..high(address_str)]:
+    for i,c in addressStr[v4StartPos..high(addressStr)]:
       if c in strutils.Digits: # Character is a number
         currentShort = currentShort * 10 + cast[uint32](ord(c) - ord('0'))
         if currentShort > 255'u32:
@@ -386,21 +386,21 @@ proc parseIPv6Address(address_str: string): IpAddress =
     raise newException(ValueError,
       "Invalid IP Address. The address consists of too many groups")
 
-proc parseIpAddress*(address_str: string): IpAddress =
+proc parseIpAddress*(addressStr: string): IpAddress =
   ## Parses an IP address
   ## Raises EInvalidValue on error
-  if address_str == nil:
-    raise newException(ValueError, "IP Address string is nil")
-  if address_str.contains(':'):
-    return parseIPv6Address(address_str)
+  if addressStr.len == 0:
+    raise newException(ValueError, "IP Address string is empty")
+  if addressStr.contains(':'):
+    return parseIPv6Address(addressStr)
   else:
-    return parseIPv4Address(address_str)
+    return parseIPv4Address(addressStr)
 
-proc isIpAddress*(address_str: string): bool {.tags: [].} =
+proc isIpAddress*(addressStr: string): bool {.tags: [].} =
   ## Checks if a string is an IP address
   ## Returns true if it is, false otherwise
   try:
-    discard parseIpAddress(address_str)
+    discard parseIpAddress(addressStr)
   except ValueError:
     return false
   return true
@@ -587,7 +587,7 @@ when defineSsl:
   proc pskClientCallback(ssl: SslPtr; hint: cstring; identity: cstring; max_identity_len: cuint; psk: ptr cuchar;
     max_psk_len: cuint): cuint {.cdecl.} =
     let ctx = SSLContext(context: ssl.SSL_get_SSL_CTX)
-    let hintString = if hint == nil: nil else: $hint
+    let hintString = if hint == nil: "" else: $hint
     let (identityString, pskString) = (ctx.clientGetPskFunc)(hintString)
     if psk.len.cuint > max_psk_len:
       return 0
@@ -657,7 +657,7 @@ when defineSsl:
 
   proc wrapConnectedSocket*(ctx: SSLContext, socket: Socket,
                             handshake: SslHandshakeType,
-                            hostname: string = nil) =
+                            hostname: string = "") =
     ## Wraps a connected socket in an SSL context. This function effectively
     ## turns ``socket`` into an SSL socket.
     ## ``hostname`` should be specified so that the client knows which hostname
@@ -671,7 +671,7 @@ when defineSsl:
     wrapSocket(ctx, socket)
     case handshake
     of handshakeAsClient:
-      if not hostname.isNil and not isIpAddress(hostname):
+      if hostname.len > 0 and not isIpAddress(hostname):
         # Discard result in case OpenSSL version doesn't support SNI, or we're
         # not using TLSv1+
         discard SSL_set_tlsext_host_name(socket.sslHandle, hostname)
diff --git a/lib/pure/parseopt2.nim b/lib/pure/parseopt2.nim
index b54a56c0c..51a70b6d1 100644
--- a/lib/pure/parseopt2.nim
+++ b/lib/pure/parseopt2.nim
@@ -44,10 +44,10 @@ type
 proc initOptParser*(cmdline: seq[string]): OptParser {.rtl.} =
   ## Initalizes option parses with cmdline. cmdline should not contain
   ## argument 0 - program name.
-  ## If cmdline == nil default to current command line arguments.
+  ## If cmdline.len == 0 default to current command line arguments.
   result.remainingShortOptions = ""
   when not defined(createNimRtl):
-    if cmdline == nil:
+    if cmdline.len == 0:
       result.cmd = commandLineParams()
       return
   else:
@@ -60,7 +60,7 @@ proc initOptParser*(cmdline: string): OptParser {.rtl, deprecated.} =
   ## and calls initOptParser(openarray[string])
   ## Do not use.
   if cmdline == "": # backward compatibility
-    return initOptParser(seq[string](nil))
+    return initOptParser(@[])
   else:
     return initOptParser(cmdline.split)
 
diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim
index e0000aad3..fe933fb79 100644
--- a/lib/pure/parsexml.nim
+++ b/lib/pure/parsexml.nim
@@ -95,6 +95,7 @@ type
     kind: XmlEventKind
     err: XmlErrorKind
     state: ParserState
+    cIsEmpty: bool
     filename: string
     options: set[XmlParseOption]
 
@@ -125,7 +126,8 @@ proc open*(my: var XmlParser, input: Stream, filename: string,
   my.kind = xmlError
   my.a = ""
   my.b = ""
-  my.c = nil
+  my.c = ""
+  my.cIsEmpty = true
   my.options = options
 
 proc close*(my: var XmlParser) {.inline.} =
@@ -482,6 +484,7 @@ proc parseTag(my: var XmlParser) =
     my.kind = xmlElementOpen
     my.state = stateAttr
     my.c = my.a # save for later
+    my.cIsEmpty = false
   else:
     my.kind = xmlElementStart
     let slash = my.buf[my.bufpos] == '/'
@@ -490,7 +493,8 @@ proc parseTag(my: var XmlParser) =
     if slash and my.buf[my.bufpos] == '>':
       inc(my.bufpos)
       my.state = stateEmptyElementTag
-      my.c = nil
+      my.c = ""
+      my.cIsEmpty = true
     elif my.buf[my.bufpos] == '>':
       inc(my.bufpos)
     else:
@@ -678,7 +682,7 @@ proc next*(my: var XmlParser) =
   of stateEmptyElementTag:
     my.state = stateNormal
     my.kind = xmlElementEnd
-    if not my.c.isNil:
+    if not my.cIsEmpty:
       my.a = my.c
   of stateError:
     my.kind = xmlError
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index d16527a56..02a2d6900 100644
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -765,7 +765,7 @@ template fillMatches(s, caps, c) =
     if startIdx != -1:
       caps[k] = substr(s, startIdx, endIdx)
     else:
-      caps[k] = nil
+      caps[k] = ""
 
 proc matchLen*(s: string, pattern: Peg, matches: var openArray[string],
                start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =
@@ -1854,7 +1854,7 @@ when isMainModule:
   assert match("prefix/start", peg"^start$", 7)
 
   if "foo" =~ peg"{'a'}?.*":
-    assert matches[0] == nil
+    assert matches[0].len == 0
   else: assert false
 
   if "foo" =~ peg"{''}.*":
diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim
index 9b9cdb52a..fb371cdce 100644
--- a/lib/pure/ropes.nim
+++ b/lib/pure/ropes.nim
@@ -37,7 +37,7 @@ type
     length: int
     data: string # != nil if a leaf
 
-proc isConc(r: Rope): bool {.inline.} = return isNil(r.data)
+proc isConc(r: Rope): bool {.inline.} = return r.length > 0
 
 # Note that the left and right pointers are not needed for leafs.
 # Leaves have relatively high memory overhead (~30 bytes on a 32
@@ -50,12 +50,12 @@ proc isConc(r: Rope): bool {.inline.} = return isNil(r.data)
 proc len*(a: Rope): int {.rtl, extern: "nro$1".} =
   ## the rope's length
   if a == nil: result = 0
-  else: result = a.length
+  else: result = abs a.length
 
 proc newRope(): Rope = new(result)
 proc newRope(data: string): Rope =
   new(result)
-  result.length = len(data)
+  result.length = -len(data)
   result.data = data
 
 var
@@ -129,7 +129,7 @@ proc insertInCache(s: string, tree: Rope): Rope =
       result.left = t
       t.right = nil
 
-proc rope*(s: string = nil): Rope {.rtl, extern: "nro$1Str".} =
+proc rope*(s: string = ""): Rope {.rtl, extern: "nro$1Str".} =
   ## Converts a string to a rope.
   if s.len == 0:
     result = nil
@@ -170,17 +170,7 @@ proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} =
     result = a
   else:
     result = newRope()
-    result.length = a.length + b.length
-    when false:
-      # XXX rebalancing would be nice, but is too expensive.
-      result.left = a.left
-      var x = newRope()
-      x.left = a.right
-      x.right = b
-      result.right = x
-    else:
-      result.left = a
-      result.right = b
+    result.length = abs(a.length) + abs(b.length)
 
 proc `&`*(a: Rope, b: string): Rope {.rtl, extern: "nroConcRopeStr".} =
   ## the concatenation operator for ropes.
@@ -229,7 +219,6 @@ iterator leaves*(r: Rope): string =
         stack.add(it.right)
         it = it.left
         assert(it != nil)
-      assert(it.data != nil)
       yield it.data
 
 iterator items*(r: Rope): char =
@@ -250,54 +239,6 @@ proc `$`*(r: Rope): string  {.rtl, extern: "nroToString".}=
   result = newStringOfCap(r.len)
   for s in leaves(r): add(result, s)
 
-when false:
-  # Format string caching seems reasonable: All leaves can be shared and format
-  # string parsing has to be done only once. A compiled format string is stored
-  # as a rope. A negative length is used for the index into the args array.
-  proc compiledArg(idx: int): Rope =
-    new(result)
-    result.length = -idx
-
-  proc compileFrmt(frmt: string): Rope =
-    var i = 0
-    var length = len(frmt)
-    result = nil
-    var num = 0
-    while i < length:
-      if frmt[i] == '$':
-        inc(i)
-        case frmt[i]
-        of '$':
-          add(result, "$")
-          inc(i)
-        of '#':
-          inc(i)
-          add(result, compiledArg(num+1))
-          inc(num)
-        of '0'..'9':
-          var j = 0
-          while true:
-            j = j * 10 + ord(frmt[i]) - ord('0')
-            inc(i)
-            if frmt[i] notin {'0'..'9'}: break
-          add(s, compiledArg(j))
-        of '{':
-          inc(i)
-          var j = 0
-          while frmt[i] in {'0'..'9'}:
-            j = j * 10 + ord(frmt[i]) - ord('0')
-            inc(i)
-          if frmt[i] == '}': inc(i)
-          else: raise newException(EInvalidValue, "invalid format string")
-          add(s, compiledArg(j))
-        else: raise newException(EInvalidValue, "invalid format string")
-      var start = i
-      while i < length:
-        if frmt[i] != '$': inc(i)
-        else: break
-      if i - 1 >= start:
-        add(result, substr(frmt, start, i-1))
-
 proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
   rtl, extern: "nroFormat".} =
   ## `%` substitution operator for ropes. Does not support the ``$identifier``
diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim
index c2c674b84..d9b863a52 100644
--- a/lib/pure/smtp.nim
+++ b/lib/pure/smtp.nim
@@ -119,8 +119,7 @@ proc newSmtp*(useSsl = false, debug=false,
     when compiledWithSsl:
       sslContext.wrapSocket(result.sock)
     else:
-      raise newException(SystemError,
-                         "SMTP module compiled without SSL support")
+      {.error: "SMTP module compiled without SSL support".}
 
 proc newAsyncSmtp*(useSsl = false, debug=false,
                    sslContext = defaultSslContext): AsyncSmtp =
@@ -133,8 +132,7 @@ proc newAsyncSmtp*(useSsl = false, debug=false,
     when compiledWithSsl:
       sslContext.wrapSocket(result.sock)
     else:
-      raise newException(SystemError,
-                         "SMTP module compiled without SSL support")
+      {.error: "SMTP module compiled without SSL support".}
 
 proc quitExcpt(smtp: AsyncSmtp, msg: string): Future[void] =
   var retFuture = newFuture[void]()
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index 1ab73faea..09626136f 100644
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -377,7 +377,10 @@ when not defined(js):
 
   proc ssClose(s: Stream) =
     var s = StringStream(s)
-    s.data = nil
+    when defined(nimNoNilSeqs):
+      s.data = ""
+    else:
+      s.data = nil
 
   proc newStringStream*(s: string = ""): StringStream =
     ## creates a new stream from the string `s`.
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index be7ff60a2..33f153587 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -358,9 +358,6 @@ proc isNilOrEmpty*(s: string): bool {.noSideEffect, procvar, rtl,
 
 proc isNilOrWhitespace*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nsuIsNilOrWhitespace".} =
   ## Checks if `s` is nil or consists entirely of whitespace characters.
-  if len(s) == 0:
-    return true
-
   result = true
   for c in s:
     if not c.isSpaceAscii():
@@ -1378,9 +1375,11 @@ proc find*(s: string, sub: char, start: Natural = 0, last: Natural = 0): int {.n
       if sub == s[i]: return i
   else:
     when hasCStringBuiltin:
-      let found = c_memchr(s[start].unsafeAddr, sub, last-start+1)
-      if not found.isNil:
-        return cast[ByteAddress](found) -% cast[ByteAddress](s.cstring)
+      let L = last-start+1
+      if L > 0:
+        let found = c_memchr(s[start].unsafeAddr, sub, L)
+        if not found.isNil:
+          return cast[ByteAddress](found) -% cast[ByteAddress](s.cstring)
     else:
       for i in start..last:
         if sub == s[i]: return i
@@ -1527,7 +1526,7 @@ proc replace*(s, sub: string, by = ""): string {.noSideEffect,
   elif subLen == 1:
     # when the pattern is a single char, we use a faster
     # char-based search that doesn't need a skip table:
-    var c = sub[0]
+    let c = sub[0]
     let last = s.high
     var i = 0
     while true:
diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim
index aa07a4fa6..757bf4745 100644
--- a/lib/pure/unittest.nim
+++ b/lib/pure/unittest.nim
@@ -176,10 +176,7 @@ method suiteEnded*(formatter: OutputFormatter) {.base, gcsafe.} =
   discard
 
 proc addOutputFormatter*(formatter: OutputFormatter) =
-  if formatters == nil:
-    formatters = @[formatter]
-  else:
-    formatters.add(formatter)
+  formatters.add(formatter)
 
 proc newConsoleOutputFormatter*(outputLevel: OutputLevel = PRINT_ALL,
                                 colorOutput = true): ConsoleOutputFormatter =
@@ -225,7 +222,7 @@ method testStarted*(formatter: ConsoleOutputFormatter, testName: string) =
   formatter.isInTest = true
 
 method failureOccurred*(formatter: ConsoleOutputFormatter, checkpoints: seq[string], stackTrace: string) =
-  if stackTrace != nil:
+  if stackTrace.len > 0:
     echo stackTrace
   let prefix = if formatter.isInSuite: "    " else: ""
   for msg in items(checkpoints):
@@ -236,7 +233,7 @@ method testEnded*(formatter: ConsoleOutputFormatter, testResult: TestResult) =
 
   if formatter.outputLevel != PRINT_NONE and
      (formatter.outputLevel == PRINT_ALL or testResult.status == FAILED):
-    let prefix = if testResult.suiteName != nil: "  " else: ""
+    let prefix = if testResult.suiteName.len > 0: "  " else: ""
     template rawPrint() = echo(prefix, "[", $testResult.status, "] ", testResult.testName)
     when not defined(ECMAScript):
       if formatter.colorOutput and not defined(ECMAScript):
@@ -301,7 +298,7 @@ method failureOccurred*(formatter: JUnitOutputFormatter, checkpoints: seq[string
   ## ``stackTrace`` is provided only if the failure occurred due to an exception.
   ## ``checkpoints`` is never ``nil``.
   formatter.testErrors.add(checkpoints)
-  if stackTrace != nil:
+  if stackTrace.len > 0:
     formatter.testStackTrace = stackTrace
 
 method testEnded*(formatter: JUnitOutputFormatter, testResult: TestResult) =
@@ -392,7 +389,7 @@ proc shouldRun(currentSuiteName, testName: string): bool =
   return false
 
 proc ensureInitialized() =
-  if formatters == nil:
+  if formatters.len == 0:
     formatters = @[OutputFormatter(defaultConsoleFormatter())]
 
   if not disabledParamFiltering and not testsFilters.isValid:
@@ -507,7 +504,7 @@ template test*(name, body) {.dirty.} =
       if testStatusIMPL == FAILED:
         programResult += 1
       let testResult = TestResult(
-        suiteName: when declared(testSuiteName): testSuiteName else: nil,
+        suiteName: when declared(testSuiteName): testSuiteName else: "",
         testName: name,
         status: testStatusIMPL
       )
@@ -555,7 +552,7 @@ template fail* =
     when declared(stackTrace):
       formatter.failureOccurred(checkpoints, stackTrace)
     else:
-      formatter.failureOccurred(checkpoints, nil)
+      formatter.failureOccurred(checkpoints, "")
 
   when not defined(ECMAScript):
     if abortOnError: quit(programResult)
diff --git a/lib/pure/xmldom.nim b/lib/pure/xmldom.nim
index 8cd47aa39..1a9e4ae26 100644
--- a/lib/pure/xmldom.nim
+++ b/lib/pure/xmldom.nim
@@ -217,9 +217,9 @@ proc createAttribute*(doc: PDocument, name: string): PAttr =
   new(attrNode)
   attrNode.fName = name
   attrNode.fNodeName = name
-  attrNode.fLocalName = nil
-  attrNode.prefix = nil
-  attrNode.fNamespaceURI = nil
+  attrNode.fLocalName = ""
+  attrNode.prefix = ""
+  attrNode.fNamespaceURI = ""
   attrNode.value = ""
   attrNode.fSpecified = false
   return attrNode
@@ -254,7 +254,7 @@ proc createAttributeNS*(doc: PDocument, namespaceURI: string, qualifiedName: str
     attrNode.prefix = qualifiedName.split(':')[0]
     attrNode.fLocalName = qualifiedName.split(':')[1]
   else:
-    attrNode.prefix = nil
+    attrNode.prefix = ""
     attrNode.fLocalName = qualifiedName
   attrNode.value = ""
 
@@ -298,9 +298,9 @@ proc createElement*(doc: PDocument, tagName: string): PElement =
   new(elNode)
   elNode.fTagName = tagName
   elNode.fNodeName = tagName
-  elNode.fLocalName = nil
-  elNode.prefix = nil
-  elNode.fNamespaceURI = nil
+  elNode.fLocalName = ""
+  elNode.prefix = ""
+  elNode.fNamespaceURI = ""
   elNode.childNodes = @[]
   elNode.attributes = @[]
 
@@ -332,7 +332,7 @@ proc createElementNS*(doc: PDocument, namespaceURI: string, qualifiedName: strin
     elNode.prefix = qualifiedName.split(':')[0]
     elNode.fLocalName = qualifiedName.split(':')[1]
   else:
-    elNode.prefix = nil
+    elNode.prefix = ""
     elNode.fLocalName = qualifiedName
   elNode.fNamespaceURI = namespaceURI
   elNode.childNodes = @[]
@@ -893,22 +893,22 @@ proc tagName*(el: PElement): string =
 proc getAttribute*(el: PNode, name: string): string =
   ## Retrieves an attribute value by ``name``
   if isNil(el.attributes):
-    return nil
+    return ""
   var attribute = el.attributes.getNamedItem(name)
   if not isNil(attribute):
     return attribute.value
   else:
-    return nil
+    return ""
 
 proc getAttributeNS*(el: PNode, namespaceURI: string, localName: string): string =
   ## Retrieves an attribute value by ``localName`` and ``namespaceURI``
   if isNil(el.attributes):
-    return nil
+    return ""
   var attribute = el.attributes.getNamedItemNS(namespaceURI, localName)
   if not isNil(attribute):
     return attribute.value
   else:
-    return nil
+    return ""
 
 proc getAttributeNode*(el: PElement, name: string): PAttr =
   ## Retrieves an attribute node by ``name``
diff --git a/lib/pure/xmldomparser.nim b/lib/pure/xmldomparser.nim
index 7c7f7b99c..8d995102e 100644
--- a/lib/pure/xmldomparser.nim
+++ b/lib/pure/xmldomparser.nim
@@ -119,7 +119,7 @@ proc loadXMLStream*(stream: Stream): PDocument =
   ## a ``PDocument``
 
   var x: XmlParser
-  open(x, stream, nil, {reportComments})
+  open(x, stream, "", {reportComments})
 
   var xmlDoc: PDocument
   var dom: PDOMImplementation = getDOM()
@@ -161,7 +161,7 @@ when not defined(testing) and isMainModule:
   #echo(xml.getElementsByTagName("bla:test")[0].namespaceURI)
   #echo(xml.getElementsByTagName("test")[0].namespaceURI)
   for i in items(xml.getElementsByTagName("*")):
-    if i.namespaceURI != nil:
+    if i.namespaceURI.len > 0:
       echo(i.nodeName, "=", i.namespaceURI)
 
 
diff --git a/lib/system.nim b/lib/system.nim
index de6e96611..d33344d0a 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -484,141 +484,103 @@ type
     raise_id: uint # set when exception is raised
     up: ref Exception # used for stacking exceptions. Not exported!
 
-  SystemError* = object of Exception ## \
-    ## Abstract class for exceptions that the runtime system raises.
-    ##
-    ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
-  IOError* = object of SystemError ## \
+  Defect* = object of Exception ## \
+    ## Abstract base class for all exceptions that Nim's runtime raises
+    ## but that are strictly uncatchable as they can also be mapped to
+    ## a ``quit`` / ``trap`` / ``exit`` operation.
+
+  CatchableError* = object of Exception ## \
+    ## Abstract class for all exceptions that are catchable.
+  IOError* = object of CatchableError ## \
     ## Raised if an IO error occurred.
-    ##
-    ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
   EOFError* = object of IOError ## \
     ## Raised if an IO "end of file" error occurred.
-    ##
-    ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
-  OSError* = object of SystemError ## \
+  OSError* = object of CatchableError ## \
     ## Raised if an operating system service failed.
-    ##
-    ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
     errorCode*: int32 ## OS-defined error code describing this error.
   LibraryError* = object of OSError ## \
     ## Raised if a dynamic library could not be loaded.
-    ##
-    ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
-  ResourceExhaustedError* = object of SystemError ## \
+  ResourceExhaustedError* = object of CatchableError ## \
     ## Raised if a resource request could not be fulfilled.
-    ##
-    ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
-  ArithmeticError* = object of Exception ## \
+  ArithmeticError* = object of Defect ## \
     ## Raised if any kind of arithmetic error occurred.
-    ##
-    ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
   DivByZeroError* = object of ArithmeticError ## \
     ## Raised for runtime integer divide-by-zero errors.
-    ##
-    ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
 
   OverflowError* = object of ArithmeticError ## \
     ## Raised for runtime integer overflows.
     ##
     ## This happens for calculations whose results are too large to fit in the
-    ## provided bits.  See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
-  AccessViolationError* = object of Exception ## \
+    ## provided bits.
+  AccessViolationError* = object of Defect ## \
     ## Raised for invalid memory access errors
-    ##
-    ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
-  AssertionError* = object of Exception ## \
+  AssertionError* = object of Defect ## \
     ## Raised when assertion is proved wrong.
     ##
-    ## Usually the result of using the `assert() template <#assert>`_.  See the
-    ## full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
-  ValueError* = object of Exception ## \
+    ## Usually the result of using the `assert() template <#assert>`_.
+  ValueError* = object of Defect ## \
     ## Raised for string and object conversion errors.
   KeyError* = object of ValueError ## \
     ## Raised if a key cannot be found in a table.
     ##
     ## Mostly used by the `tables <tables.html>`_ module, it can also be raised
     ## by other collection modules like `sets <sets.html>`_ or `strtabs
-    ## <strtabs.html>`_. See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
-  OutOfMemError* = object of SystemError ## \
+    ## <strtabs.html>`_.
+  OutOfMemError* = object of Defect ## \
     ## Raised for unsuccessful attempts to allocate memory.
-    ##
-    ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
-  IndexError* = object of Exception ## \
+  IndexError* = object of Defect ## \
     ## Raised if an array index is out of bounds.
-    ##
-    ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
 
-  FieldError* = object of Exception ## \
+  FieldError* = object of Defect ## \
     ## Raised if a record field is not accessible because its dicriminant's
     ## value does not fit.
-    ##
-    ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
-  RangeError* = object of Exception ## \
+  RangeError* = object of Defect ## \
     ## Raised if a range check error occurred.
-    ##
-    ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
-  StackOverflowError* = object of SystemError ## \
+  StackOverflowError* = object of Defect ## \
     ## Raised if the hardware stack used for subroutine calls overflowed.
-    ##
-    ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
-  ReraiseError* = object of Exception ## \
+  ReraiseError* = object of Defect ## \
     ## Raised if there is no exception to reraise.
-    ##
-    ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
-  ObjectAssignmentError* = object of Exception ## \
+  ObjectAssignmentError* = object of Defect ## \
     ## Raised if an object gets assigned to its parent's object.
-    ##
-    ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
-  ObjectConversionError* = object of Exception ## \
+  ObjectConversionError* = object of Defect ## \
     ## Raised if an object is converted to an incompatible object type.
     ## You can use ``of`` operator to check if conversion will succeed.
-    ##
-    ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
-  FloatingPointError* = object of Exception ## \
+  FloatingPointError* = object of Defect ## \
     ## Base class for floating point exceptions.
-    ##
-    ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
   FloatInvalidOpError* = object of FloatingPointError ## \
     ## Raised by invalid operations according to IEEE.
     ##
-    ## Raised by ``0.0/0.0``, for example.  See the full `exception
-    ## hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
+    ## Raised by ``0.0/0.0``, for example.
   FloatDivByZeroError* = object of FloatingPointError ## \
     ## Raised by division by zero.
     ##
-    ## Divisor is zero and dividend is a finite nonzero number.  See the full
-    ## `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
+    ## Divisor is zero and dividend is a finite nonzero number.
   FloatOverflowError* = object of FloatingPointError ## \
     ## Raised for overflows.
     ##
     ## The operation produced a result that exceeds the range of the exponent.
-    ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
   FloatUnderflowError* = object of FloatingPointError ## \
     ## Raised for underflows.
     ##
     ## The operation produced a result that is too small to be represented as a
-    ## normal number. See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
+    ## normal number.
   FloatInexactError* = object of FloatingPointError ## \
     ## Raised for inexact results.
     ##
     ## The operation produced a result that cannot be represented with infinite
     ## precision -- for example: ``2.0 / 3.0, log(1.1)``
     ##
-    ## **NOTE**: Nim currently does not detect these!  See the full
-    ## `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
-  DeadThreadError* = object of Exception ## \
+    ## **NOTE**: Nim currently does not detect these!
+  DeadThreadError* = object of Defect ## \
     ## Raised if it is attempted to send a message to a dead thread.
-    ##
-    ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
-  NilAccessError* = object of SystemError ## \
+  NilAccessError* = object of Defect ## \
     ## Raised on dereferences of ``nil`` pointers.
     ##
     ## This is only raised if the ``segfaults.nim`` module was imported!
 
 when defined(nimNewRuntime):
   type
-    MoveError* = object of SystemError ## \
+    MoveError* = object of Defect ## \
       ## Raised on attempts to re-sink an already consumed ``sink`` parameter.
 
 when defined(js) or defined(nimdoc):
@@ -2321,9 +2283,9 @@ iterator mpairs*(a: var cstring): tuple[key: int, val: var char] {.inline.} =
     inc(i)
 
 
-proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil".}
+proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil", deprecated.}
 proc isNil*[T](x: ref T): bool {.noSideEffect, magic: "IsNil".}
-proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil".}
+proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil", deprecated.}
 proc isNil*[T](x: ptr T): bool {.noSideEffect, magic: "IsNil".}
 proc isNil*(x: pointer): bool {.noSideEffect, magic: "IsNil".}
 proc isNil*(x: cstring): bool {.noSideEffect, magic: "IsNil".}
@@ -2382,8 +2344,12 @@ proc `==`*[T](x, y: seq[T]): bool {.noSideEffect.} =
   ## Generic equals operator for sequences: relies on a equals operator for
   ## the element type `T`.
   when nimvm:
-    if x.isNil and y.isNil:
-      return true
+    when not defined(nimNoNil):
+      if x.isNil and y.isNil:
+        return true
+    else:
+      if x.len == 0 and y.len == 0:
+        return true
   else:
     when not defined(JS):
       proc seqToPtr[T](x: seq[T]): pointer {.inline, nosideeffect.} =
@@ -2520,7 +2486,7 @@ proc `$`*[T: tuple|object](x: T): string =
     result.add(name)
     result.add(": ")
     when compiles($value):
-      when compiles(value.isNil):
+      when value isnot string and value isnot seq and compiles(value.isNil):
         if value.isNil: result.add "nil"
         else: result.addQuoted(value)
       else:
@@ -2539,7 +2505,7 @@ proc collectionToString[T](x: T, prefix, separator, suffix: string): string =
     else:
       result.add(separator)
 
-    when compiles(value.isNil):
+    when value isnot string and value isnot seq and compiles(value.isNil):
       # this branch should not be necessary
       if value.isNil:
         result.add "nil"
@@ -4001,19 +3967,28 @@ when hasAlloc:
   proc safeAdd*[T](x: var seq[T], y: T) {.noSideEffect, deprecated.} =
     ## Adds ``y`` to ``x`` unless ``x`` is not yet initialized; in that case,
     ## ``x`` becomes ``@[y]``
-    if x == nil: x = @[y]
-    else: x.add(y)
+    when defined(nimNoNilSeqs):
+      x.add(y)
+    else:
+      if x == nil: x = @[y]
+      else: x.add(y)
 
   proc safeAdd*(x: var string, y: char) {.noSideEffect, deprecated.} =
     ## Adds ``y`` to ``x``. If ``x`` is ``nil`` it is initialized to ``""``
-    if x == nil: x = ""
-    x.add(y)
+    when defined(nimNoNilSeqs):
+      x.add(y)
+    else:
+      if x == nil: x = ""
+      x.add(y)
 
   proc safeAdd*(x: var string, y: string) {.noSideEffect, deprecated.} =
     ## Adds ``y`` to ``x`` unless ``x`` is not yet initalized; in that
     ## case, ``x`` becomes ``y``
-    if x == nil: x = y
-    else: x.add(y)
+    when defined(nimNoNilSeqs):
+      x.add(y)
+    else:
+      if x == nil: x = y
+      else: x.add(y)
 
 proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} =
   ## generates a tuple constructor expression listing all the local variables
@@ -4073,6 +4048,11 @@ proc `==`*(x, y: cstring): bool {.magic: "EqCString", noSideEffect,
   elif x.isNil or y.isNil: result = false
   else: result = strcmp(x, y) == 0
 
+when defined(nimNoNilSeqs2):
+  when not compileOption("nilseqs"):
+    proc `==`*(x: string; y: type(nil)): bool {.error.} = discard
+    proc `==`*(x: type(nil); y: string): bool {.error.} = discard
+
 template closureScope*(body: untyped): untyped =
   ## Useful when creating a closure in a loop to capture local loop variables by
   ## their current iteration values. Example:
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
index e12bab184..8d4a2e482 100644
--- a/lib/system/jssys.nim
+++ b/lib/system/jssys.nim
@@ -110,7 +110,7 @@ proc getStackTrace*(e: ref Exception): string = e.trace
 proc unhandledException(e: ref Exception) {.
     compilerproc, asmNoStackFrame.} =
   var buf = ""
-  if e.msg != nil and e.msg[0] != '\0':
+  if e.msg.len != 0:
     add(buf, "Error: unhandled exception: ")
     add(buf, e.msg)
   else:
diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim
index 19c2c62ad..0e690d832 100644
--- a/lib/system/sysstr.nim
+++ b/lib/system/sysstr.nim
@@ -95,6 +95,7 @@ proc mnewString(len: int): NimString {.compilerProc.} =
 
 proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} =
   let start = max(start, 0)
+  if s == nil: return nil
   let len = min(last, s.len-1) - start + 1
   if len > 0:
     result = rawNewStringNoInit(len)
@@ -109,6 +110,7 @@ proc nimToCStringConv(s: NimString): cstring {.compilerProc, inline.} =
   else: result = cstring(addr s.data)
 
 proc copyStr(s: NimString, start: int): NimString {.compilerProc.} =
+  if s == nil: return nil
   result = copyStrLast(s, start, s.len-1)
 
 proc toNimStr(str: cstring, len: int): NimString {.compilerProc.} =