summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2018-08-13 11:41:33 +0200
committerAndreas Rumpf <rumpf_a@web.de>2018-08-13 11:41:33 +0200
commitdae5450947e93e2e5222ae2710874186bf27bf39 (patch)
treeddb9da438bb516d81491af41ef646abf34d67406
parent32afc1a562579d38e82ebb385186767dfb1bc3c8 (diff)
downloadNim-dae5450947e93e2e5222ae2710874186bf27bf39.tar.gz
WIP: disallow 'nil' for strings and seqs
-rw-r--r--compiler/ast.nim12
-rw-r--r--compiler/ccgcalls.nim4
-rw-r--r--compiler/ccgexprs.nim3
-rw-r--r--compiler/ccgmerge.nim2
-rw-r--r--compiler/commands.nim1
-rw-r--r--compiler/condsyms.nim1
-rw-r--r--compiler/docgen.nim15
-rw-r--r--compiler/jsgen.nim4
-rw-r--r--compiler/lineinfos.nim14
-rw-r--r--compiler/lookups.nim2
-rw-r--r--compiler/msgs.nim8
-rw-r--r--compiler/options.nim3
-rw-r--r--compiler/parser.nim3
-rw-r--r--compiler/patterns.nim5
-rw-r--r--compiler/renderer.nim16
-rw-r--r--compiler/ropes.nim26
-rw-r--r--compiler/scriptconfig.nim2
-rw-r--r--compiler/sem.nim2
-rw-r--r--compiler/semcall.nim6
-rw-r--r--compiler/semdata.nim7
-rw-r--r--compiler/seminst.nim7
-rw-r--r--compiler/semobjconstr.nim4
-rw-r--r--compiler/semstmts.nim5
-rw-r--r--compiler/semtypinst.nim4
-rw-r--r--compiler/sigmatch.nim22
-rw-r--r--compiler/types.nim9
-rw-r--r--lib/impure/re.nim8
-rw-r--r--lib/packages/docutils/rstast.nim4
-rw-r--r--lib/packages/docutils/rstgen.nim9
-rw-r--r--lib/pure/asyncfutures.nim4
-rw-r--r--lib/pure/asyncnet.nim4
-rw-r--r--lib/pure/collections/intsets.nim24
-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.nim2
-rw-r--r--lib/pure/streams.nim5
-rw-r--r--lib/pure/unittest.nim13
-rw-r--r--lib/pure/xmldom.nim24
-rw-r--r--lib/pure/xmldomparser.nim4
-rw-r--r--lib/system.nim21
-rw-r--r--tests/async/tasync_misc.nim3
-rw-r--r--tests/async/tasyncssl.nim4
43 files changed, 207 insertions, 173 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index ef12e1184..7d8d098e3 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -1150,7 +1150,10 @@ proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) =
   for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
 
 proc discardSons*(father: PNode) =
-  father.sons = nil
+  when defined(nimNoNilSeqs):
+    father.sons = @[]
+  else:
+    father.sons = nil
 
 proc withInfo*(n: PNode, info: TLineInfo): PNode =
   n.info = info
@@ -1367,7 +1370,7 @@ proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo;
   result.loc = s.loc
   result.annex = s.annex
   # XXX once usedGenerics is used, ensure module aliases keep working!
-  assert s.usedGenerics == nil
+  assert s.usedGenerics.len == 0
 
 proc initStrTable*(x: var TStrTable) =
   x.counter = 0
@@ -1592,7 +1595,10 @@ proc getStr*(a: PNode): string =
   of nkStrLit..nkTripleStrLit: result = a.strVal
   of nkNilLit:
     # let's hope this fixes more problems than it creates:
-    result = nil
+    when defined(nimNoNilSeqs):
+      result = ""
+    else:
+      result = nil
   else:
     doAssert false, "getStr"
     #internalError(a.info, "getStr")
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 9712d5dce..2621574a6 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -431,7 +431,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
   assert(sonsLen(typ) == sonsLen(typ.n))
   # don't call '$' here for efficiency:
   let pat = ri.sons[0].sym.loc.r.data
-  internalAssert p.config, pat != nil
+  internalAssert p.config, pat.len > 0
   if pat.contains({'#', '(', '@', '\''}):
     var pl = genPatternCall(p, ri, pat, typ)
     # simpler version of 'fixupCall' that works with the pl+params combination:
@@ -480,7 +480,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
 
   # don't call '$' here for efficiency:
   let pat = ri.sons[0].sym.loc.r.data
-  internalAssert p.config, pat != nil
+  internalAssert p.config, pat.len > 0
   var start = 3
   if ' ' in pat:
     start = 1
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index e8bb70f13..dd1c72ab6 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -65,7 +65,8 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
     of tyString:
       # with the new semantics for 'nil' strings, we can map "" to nil and
       # save tons of allocations:
-      if n.strVal.len == 0: result = genNilStringLiteral(p.module, n.info)
+      if n.strVal.len == 0 and optNilSeqs notin p.options:
+        result = genNilStringLiteral(p.module, n.info)
       else:
         result = genStringLiteral(p.module, n)
     else:
diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim
index 664f89b73..067a60c57 100644
--- a/compiler/ccgmerge.nim
+++ b/compiler/ccgmerge.nim
@@ -58,7 +58,7 @@ proc genSectionEnd*(fs: TCFileSection; conf: ConfigRef): Rope =
 
 proc genSectionStart*(ps: TCProcSection; conf: ConfigRef): Rope =
   if compilationCachePresent(conf):
-    result = rope(nil)
+    result = rope("")
     add(result, "\n/*\t")
     add(result, CProcSectionNames[ps])
     add(result, ":*/\n")
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 866405f9f..aae976038 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -496,6 +496,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
     else:
       localError(conf, info, errOnOrOffExpectedButXFound % arg)
   of "laxstrings": processOnOffSwitch(conf, {optLaxStrings}, arg, pass, info)
+  of "nilseqs": processOnOffSwitch(conf, {optNilSeqs}, arg, pass, info)
   of "checks", "x": processOnOffSwitch(conf, ChecksOptions, arg, pass, info)
   of "floatchecks":
     processOnOffSwitch(conf, {optNaNCheck, optInfCheck}, arg, pass, info)
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index 5a62b46ad..1f147b4a8 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -74,3 +74,4 @@ proc initDefines*(symbols: StringTableRef) =
   defineSymbol("nimVmExportFixed")
   defineSymbol("nimIncrSeqV3")
   defineSymbol("nimAshr")
+  defineSymbol("nimNoNilSeqs")
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 8d233566c..b35452365 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -191,7 +191,7 @@ proc ropeFormatNamedVars(conf: ConfigRef; frmt: FormatStr,
 proc genComment(d: PDoc, n: PNode): string =
   result = ""
   var dummyHasToc: bool
-  if n.comment != nil:
+  if n.comment.len > 0:
     renderRstToOut(d[], parseRst(n.comment, toFilename(d.conf, n.info),
                                toLinenumber(n.info), toColumn(n.info),
                                dummyHasToc, d.options, d.conf), result)
@@ -205,7 +205,8 @@ proc genRecComment(d: PDoc, n: PNode): Rope =
         result = genRecComment(d, n.sons[i])
         if result != nil: return
   else:
-    n.comment = nil
+    when defined(nimNoNilSeqs): n.comment = ""
+    else: n.comment = nil
 
 proc getPlainDocstring(n: PNode): string =
   ## Gets the plain text docstring of a node non destructively.
@@ -215,7 +216,7 @@ proc getPlainDocstring(n: PNode): string =
   ## the concatenated ``##`` comments of the node.
   result = ""
   if n == nil: return
-  if n.comment != nil and startsWith(n.comment, "##"):
+  if startsWith(n.comment, "##"):
     result = n.comment
   if result.len < 1:
     for i in countup(0, safeLen(n)-1):
@@ -564,9 +565,9 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
 
   result = %{ "name": %name, "type": %($k), "line": %n.info.line.int,
                  "col": %n.info.col}
-  if comm != nil and comm != "":
+  if comm.len > 0:
     result["description"] = %comm
-  if r.buf != nil:
+  if r.buf.len > 0:
     result["code"] = %r.buf
 
 proc checkForFalse(n: PNode): bool =
@@ -634,7 +635,7 @@ proc add(d: PDoc; j: JsonNode) =
 proc generateJson*(d: PDoc, n: PNode) =
   case n.kind
   of nkCommentStmt:
-    if n.comment != nil and startsWith(n.comment, "##"):
+    if startsWith(n.comment, "##"):
       let stripped = n.comment.substr(2).strip
       d.add %{ "comment": %stripped, "line": %n.info.line.int,
                "col": %n.info.col }
@@ -678,7 +679,7 @@ proc genTagsItem(d: PDoc, n, nameNode: PNode, k: TSymKind): string =
 proc generateTags*(d: PDoc, n: PNode, r: var Rope) =
   case n.kind
   of nkCommentStmt:
-    if n.comment != nil and startsWith(n.comment, "##"):
+    if startsWith(n.comment, "##"):
       let stripped = n.comment.substr(2).strip
       r.add stripped
   of nkProcDef:
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 63100a68d..462c622aa 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -1267,7 +1267,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
   if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
   if sfInfixCall in f.flags:
     let pat = n.sons[0].sym.loc.r.data
-    internalAssert p.config, pat != nil
+    internalAssert p.config, pat.len > 0
     if pat.contains({'#', '(', '@'}):
       var typ = skipTypes(n.sons[0].typ, abstractInst)
       assert(typ.kind == tyProc)
@@ -1350,7 +1350,7 @@ proc arrayTypeForElemType(typ: PType): string =
   of tyUint8: "Uint8Array"
   of tyFloat32: "Float32Array"
   of tyFloat64, tyFloat: "Float64Array"
-  else: nil
+  else: ""
 
 proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
   var t = skipTypes(typ, abstractInst)
diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim
index 4f0c3a778..c5a641713 100644
--- a/compiler/lineinfos.nim
+++ b/compiler/lineinfos.nim
@@ -164,13 +164,13 @@ type
   TNoteKinds* = set[TNoteKind]
 
 proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
-    result[3] = {low(TNoteKind)..high(TNoteKind)} - {}
-    result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext}
-    result[1] = result[2] - {warnShadowIdent, warnProveField, warnProveIndex,
-      warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
-      hintSource, hintGlobalVar, hintGCStats}
-    result[0] = result[1] - {hintSuccessX, hintSuccess, hintConf,
-      hintProcessing, hintPattern, hintExecuting, hintLinking}
+  result[3] = {low(TNoteKind)..high(TNoteKind)} - {}
+  result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext}
+  result[1] = result[2] - {warnShadowIdent, warnProveField, warnProveIndex,
+    warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
+    hintSource, hintGlobalVar, hintGCStats}
+  result[0] = result[1] - {hintSuccessX, hintSuccess, hintConf,
+    hintProcessing, hintPattern, hintExecuting, hintLinking}
 
 const
   NotesVerbosity* = computeNotesVerbosity()
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index bab631e6f..1e9d963fa 100644
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -262,7 +262,7 @@ proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string) =
     err.add "\nThis might be caused by a recursive module dependency: "
     err.add c.recursiveDep
     # prevent excessive errors for 'nim check'
-    c.recursiveDep = nil
+    c.recursiveDep = ""
   localError(c.config, info, errGenerated, err)
 
 proc lookUp*(c: PContext, n: PNode): PSym =
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index be2ece911..1d7939142 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -391,10 +391,10 @@ proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) =
 
   if conf.structuredErrorHook != nil:
     conf.structuredErrorHook(conf, unknownLineInfo(),
-      s & (if kind != nil: KindFormat % kind else: ""), sev)
+      s & (if kind.len > 0: KindFormat % kind else: ""), sev)
 
   if not ignoreMsgBecauseOfIdeTools(conf, msg):
-    if kind != nil:
+    if kind.len > 0:
       styledMsgWriteln(color, title, resetStyle, s,
                        KindColor, `%`(KindFormat, kind))
     else:
@@ -483,9 +483,9 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
 
   if not ignoreMsg:
     if conf.structuredErrorHook != nil:
-      conf.structuredErrorHook(conf, info, s & (if kind != nil: KindFormat % kind else: ""), sev)
+      conf.structuredErrorHook(conf, info, s & (if kind.len > 0: KindFormat % kind else: ""), sev)
     if not ignoreMsgBecauseOfIdeTools(conf, msg):
-      if kind != nil:
+      if kind.len > 0:
         styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s,
                          KindColor, `%`(KindFormat, kind))
       else:
diff --git a/compiler/options.nim b/compiler/options.nim
index 537a550f8..6de32bfad 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -38,7 +38,8 @@ type                          # please make sure we have under 32 options
     optPatterns,              # en/disable pattern matching
     optMemTracker,
     optHotCodeReloading,
-    optLaxStrings
+    optLaxStrings,
+    optNilSeqs
 
   TOptions* = set[TOption]
   TGlobalOption* = enum       # **keep binary compatible**
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 5664a9f67..98ccb05b9 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -150,7 +150,8 @@ template sameOrNoInd(p): bool = p.tok.indent == p.currInd or p.tok.indent < 0
 proc rawSkipComment(p: var TParser, node: PNode) =
   if p.tok.tokType == tkComment:
     if node != nil:
-      if node.comment == nil: node.comment = ""
+      when not defined(nimNoNilSeqs):
+        if node.comment == nil: node.comment = ""
       when defined(nimpretty):
         if p.tok.commentOffsetB > p.tok.commentOffsetA:
           add node.comment, fileSection(p.lex.config, p.lex.fileIdx, p.tok.commentOffsetA, p.tok.commentOffsetB)
diff --git a/compiler/patterns.nim b/compiler/patterns.nim
index 2d2aeba76..aa06342f9 100644
--- a/compiler/patterns.nim
+++ b/compiler/patterns.nim
@@ -209,7 +209,10 @@ proc matchStmtList(c: PPatternContext, p, n: PNode): PNode =
     for j in 0 ..< p.len:
       if not matches(c, p.sons[j], n.sons[i+j]):
         # we need to undo any bindings:
-        if not isNil(c.mapping): c.mapping = nil
+        when defined(nimNoNilSeqs):
+          c.mapping = @[]
+        else:
+          if not isNil(c.mapping): c.mapping = nil
         return false
     result = true
 
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index ce27e1cd9..c3e151f5a 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -281,7 +281,7 @@ const
 
 proc shouldRenderComment(g: var TSrcGen, n: PNode): bool =
   result = false
-  if n.comment != nil:
+  if n.comment.len > 0:
     result = (renderNoComments notin g.flags) or
         (renderDocComments in g.flags)
 
@@ -402,7 +402,7 @@ proc lsons(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int =
 proc lsub(g: TSrcGen; n: PNode): int =
   # computes the length of a tree
   if isNil(n): return 0
-  if n.comment != nil: return MaxLineLen + 1
+  if n.comment.len > 0: return MaxLineLen + 1
   case n.kind
   of nkEmpty: result = 0
   of nkTripleStrLit:
@@ -500,7 +500,7 @@ proc lsub(g: TSrcGen; n: PNode): int =
   of nkBreakStmt: result = lsub(g, n.sons[0]) + len("break_")
   of nkContinueStmt: result = lsub(g, n.sons[0]) + len("continue_")
   of nkPragma: result = lcomma(g, n) + 4
-  of nkCommentStmt: result = if n.comment.isNil: 0 else: len(n.comment)
+  of nkCommentStmt: result = len(n.comment)
   of nkOfBranch: result = lcomma(g, n, 0, - 2) + lsub(g, lastSon(n)) + len("of_:_")
   of nkImportAs: result = lsub(g, n.sons[0]) + len("_as_") + lsub(g, n.sons[1])
   of nkElifBranch: result = lsons(g, n) + len("elif_:_")
@@ -539,7 +539,7 @@ proc gsub(g: var TSrcGen, n: PNode) =
 proc hasCom(n: PNode): bool =
   result = false
   if n.isNil: return false
-  if n.comment != nil: return true
+  if n.comment.len > 0: return true
   case n.kind
   of nkEmpty..nkNilLit: discard
   else:
@@ -602,7 +602,7 @@ proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TTokType,
   dedent(g)
 
 proc longMode(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): bool =
-  result = n.comment != nil
+  result = n.comment.len > 0
   if not result:
     # check further
     for i in countup(start, sonsLen(n) + theEnd):
@@ -637,7 +637,7 @@ proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) =
 proc gcond(g: var TSrcGen, n: PNode) =
   if n.kind == nkStmtListExpr:
     put(g, tkParLe, "(")
-  gsub(g, n)  
+  gsub(g, n)
   if n.kind == nkStmtListExpr:
     put(g, tkParRi, ")")
 
@@ -864,7 +864,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
   if isNil(n): return
   var
     a: TContext
-  if n.comment != nil: pushCom(g, n)
+  if n.comment.len > 0: pushCom(g, n)
   case n.kind                 # atoms:
   of nkTripleStrLit: put(g, tkTripleStrLit, atom(g, n))
   of nkEmpty: discard
@@ -1079,7 +1079,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
                 elif n[0].kind in {nkOpenSymChoice, nkClosedSymChoice}: n[0][0].sym.name
                 else: nil
       var n_next = n[1]
-      while n_next.kind in {nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref, 
+      while n_next.kind in {nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref,
                   nkStringToCString, nkCStringToString} and n_next.len > 0:
         n_next = n_next[0]
       if n_next.kind == nkPrefix or (opr != nil and renderer.isKeyword(opr)):
diff --git a/compiler/ropes.nim b/compiler/ropes.nim
index 973f16916..81ee01dbf 100644
--- a/compiler/ropes.nim
+++ b/compiler/ropes.nim
@@ -66,29 +66,19 @@ type
   Rope* = ref RopeObj
   RopeObj*{.acyclic.} = object of RootObj # the empty rope is represented
                                           # by nil to safe space
-    left*, right*: Rope
-    length*: int
-    data*: string             # != nil if a leaf
+    left, right: Rope
+    L: int                    # <= 0 if a leaf
+    data*: string
 
 proc len*(a: Rope): int =
   ## the rope's length
   if a == nil: result = 0
-  else: result = a.length
+  else: result = abs a.L
 
-proc newRope(data: string = nil): Rope =
+proc newRope(data: string = ""): Rope =
   new(result)
-  if data != nil:
-    result.length = len(data)
-    result.data = data
-
-proc newMutableRope*(capacity = 30): Rope =
-  ## creates a new rope that supports direct modifications of the rope's
-  ## 'data' and 'length' fields.
-  new(result)
-  result.data = newStringOfCap(capacity)
-
-proc freezeMutableRope*(r: Rope) {.inline.} =
-  r.length = r.data.len
+  result.L = -len(data)
+  result.data = data
 
 var
   cache: array[0..2048*2 - 1, Rope] # XXX Global here!
@@ -147,7 +137,7 @@ proc `&`*(a, b: Rope): Rope =
     result = a
   else:
     result = newRope()
-    result.length = a.length + b.length
+    result.L = abs(a.L) + abs(b.L)
     result.left = a
     result.right = b
 
diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim
index ae7e030b8..f3d6ccfdd 100644
--- a/compiler/scriptconfig.nim
+++ b/compiler/scriptconfig.nim
@@ -45,7 +45,7 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
   template cbos(name, body) {.dirty.} =
     result.registerCallback "stdlib.system." & astToStr(name),
       proc (a: VmArgs) =
-        errorMsg = nil
+        errorMsg = ""
         try:
           body
         except OSError:
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 427b44e04..6128c02d1 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -119,7 +119,7 @@ proc commonType*(x, y: PType): PType =
   elif b.kind == tyStmt: result = b
   elif a.kind == tyTypeDesc:
     # turn any concrete typedesc into the abstract typedesc type
-    if a.sons == nil: result = a
+    if a.len == 0: result = a
     else:
       result = newType(tyTypeDesc, a.owner)
       rawAddSon(result, newType(tyNone, a.owner))
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index aa5394a71..ef452fcdc 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -89,7 +89,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
       continue
     determineType(c, sym)
     initCandidate(c, z, sym, initialBinding, scope, diagnosticsFlag)
-    if c.currentScope.symbols.counter == counterInitial or syms != nil:
+    if c.currentScope.symbols.counter == counterInitial or syms.len != 0:
       matches(c, n, orig, z)
       if z.state == csMatch:
         #if sym.name.s == "==" and (n.info ?? "temp3"):
@@ -237,7 +237,7 @@ proc bracketNotFoundError(c: PContext; n: PNode) =
     if symx.kind in routineKinds:
       errors.add(CandidateError(sym: symx,
                                 unmatchedVarParam: 0, firstMismatch: 0,
-                                diagnostics: nil,
+                                diagnostics: @[],
                                 enabled: false))
     symx = nextOverloadIter(o, c, headSymbol)
   if errors.len == 0:
@@ -455,7 +455,7 @@ proc tryDeref(n: PNode): PNode =
 
 proc semOverloadedCall(c: PContext, n, nOrig: PNode,
                        filter: TSymKinds, flags: TExprFlags): PNode =
-  var errors: CandidateErrors = if efExplain in flags: @[] else: nil
+  var errors: CandidateErrors = @[] # if efExplain in flags: @[] else: nil
   var r = resolveOverloads(c, n, nOrig, filter, flags, errors, efExplain in flags)
   if r.state == csMatch:
     # this may be triggered, when the explain pragma is used
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index aa0cb6e8e..4189a5214 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -37,6 +37,7 @@ type
                               # in standalone ``except`` and ``finally``
     next*: PProcCon           # used for stacking procedure contexts
     wasForwarded*: bool       # whether the current proc has a separate header
+    mappingExists*: bool
     mapping*: TIdTable
 
   TMatchedConcept* = object
@@ -176,12 +177,14 @@ proc lastOptionEntry*(c: PContext): POptionEntry =
 proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
 
 proc put*(p: PProcCon; key, val: PSym) =
-  if p.mapping.data == nil: initIdTable(p.mapping)
+  if not p.mappingExists:
+    initIdTable(p.mapping)
+    p.mappingExists = true
   #echo "put into table ", key.info
   p.mapping.idTablePut(key, val)
 
 proc get*(p: PProcCon; key: PSym): PSym =
-  if p.mapping.data == nil: return nil
+  if not p.mappingExists: return nil
   result = PSym(p.mapping.idTableGet(key))
 
 proc getGenSym*(c: PContext; s: PSym): PSym =
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index fac04e3a0..f9d7c3754 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -97,10 +97,9 @@ proc sameInstantiation(a, b: TInstantiation): bool =
 
 proc genericCacheGet(genericSym: PSym, entry: TInstantiation;
                      id: CompilesId): PSym =
-  if genericSym.procInstCache != nil:
-    for inst in genericSym.procInstCache:
-      if inst.compilesId == id and sameInstantiation(entry, inst[]):
-        return inst.sym
+  for inst in genericSym.procInstCache:
+    if inst.compilesId == id and sameInstantiation(entry, inst[]):
+      return inst.sym
 
 when false:
   proc `$`(x: PSym): string =
diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim
index 8b639806d..90ab2c57a 100644
--- a/compiler/semobjconstr.nim
+++ b/compiler/semobjconstr.nim
@@ -121,7 +121,7 @@ proc missingMandatoryFields(c: PContext, fieldsRecList, initExpr: PNode): string
     if {tfNotNil, tfNeedsInit} * r.sym.typ.flags != {}:
       let assignment = locateFieldInInitExpr(c, r.sym, initExpr)
       if assignment == nil:
-        if result == nil:
+        if result.len == 0:
           result = r.sym.name.s
         else:
           result.add ", "
@@ -129,7 +129,7 @@ proc missingMandatoryFields(c: PContext, fieldsRecList, initExpr: PNode): string
 
 proc checkForMissingFields(c: PContext, recList, initExpr: PNode) =
   let missing = missingMandatoryFields(c, recList, initExpr)
-  if missing != nil:
+  if missing.len > 0:
     localError(c.config, initExpr.info, "fields not initialized: $1.", [missing])
 
 proc semConstructFields(c: PContext, recNode: PNode,
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 6ef03456e..b1e39d2db 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -970,7 +970,10 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
             var body = s.typ.lastSon
             if body.kind == tyObject:
               # erases all declared fields
-              body.n.sons = nil
+              when defined(nimNoNilSeqs):
+                body.n.sons = @[]
+              else:
+                body.n.sons = nil
 
       popOwner(c)
       closeScope(c)
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index ff7cb0bb0..c315cbebb 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -40,8 +40,8 @@ proc searchInstTypes*(key: PType): PType =
   if not (genericTyp.kind == tyGenericBody and
       key.sons[0] == genericTyp and genericTyp.sym != nil): return
 
-  if genericTyp.sym.typeInstCache == nil:
-    return
+  when not defined(nimNoNilSeqs):
+    if genericTyp.sym.typeInstCache == nil: return
 
   for inst in genericTyp.sym.typeInstCache:
     if inst.id == key.id: return inst
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 5afa1b031..b26d94c90 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -143,7 +143,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
       c.calleeScope = 1
   else:
     c.calleeScope = calleeScope
-  c.diagnostics = if diagnosticsEnabled: @[] else: nil
+  c.diagnostics = @[] # if diagnosticsEnabled: @[] else: nil
   c.diagnosticsEnabled = diagnosticsEnabled
   c.magic = c.calleeSym.magic
   initIdTable(c.bindings)
@@ -535,6 +535,12 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
 proc allowsNil(f: PType): TTypeRelation {.inline.} =
   result = if tfNotNil notin f.flags: isSubtype else: isNone
 
+proc allowsNilDeprecated(c: TCandidate, f: PType): TTypeRelation =
+  if optNilSeqs in c.c.config.options:
+    result = allowsNil(f)
+  else:
+    result = isNone
+
 proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
   result = f.kind != a.kind and (f.kind in {tyVar, tyLent} or a.kind in {tyVar, tyLent})
 
@@ -741,7 +747,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
     diagnostics = @[]
     flags = {efExplain}
     m.c.config.writelnHook = proc (s: string) =
-      if errorPrefix == nil: errorPrefix = typeClass.sym.name.s & ":"
+      if errorPrefix.len == 0: errorPrefix = typeClass.sym.name.s & ":"
       let msg = s.replace("Error:", errorPrefix)
       if oldWriteHook != nil: oldWriteHook msg
       diagnostics.add msg
@@ -1253,7 +1259,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
             result = isNone
         elif tfNotNil in f.flags and tfNotNil notin a.flags:
           result = isNilConversion
-    of tyNil: result = f.allowsNil
+    of tyNil: result = allowsNilDeprecated(c, f)
     else: discard
   of tyOrdinal:
     if isOrdinalType(a):
@@ -1338,7 +1344,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
         result = isNilConversion
       else:
         result = isEqual
-    of tyNil: result = f.allowsNil
+    of tyNil: result = allowsNilDeprecated(c, f)
     else: discard
   of tyCString:
     # conversion from string to cstring is automatic:
@@ -1349,7 +1355,11 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
       else:
         result = isEqual
     of tyNil: result = f.allowsNil
-    of tyString: result = isConvertible
+    of tyString:
+      if optNilSeqs in c.c.config.options or c.magic != mEqCString:
+        result = isConvertible
+      else:
+        result = isNone
     of tyPtr:
       # ptr[Tag, char] is not convertible to 'cstring' for now:
       if a.len == 1:
@@ -1612,7 +1622,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
           if f.sonsLen == 0:
             result = isGeneric
           else:
-            internalAssert c.c.graph.config, a.sons != nil and a.sons.len > 0
+            internalAssert c.c.graph.config, a.len > 0
             c.typedescMatched = true
             var aa = a
             while aa.kind in {tyTypeDesc, tyGenericParam} and aa.len > 0:
diff --git a/compiler/types.nim b/compiler/types.nim
index 23fbc9f1b..8a120b609 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -428,7 +428,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
       result = t.sym.name.s & " literal(" & $t.n.intVal & ")"
     elif prefer in {preferName, preferTypeName} or t.sym.owner.isNil:
       result = t.sym.name.s
-      if t.kind == tyGenericParam and t.sons != nil and t.sonsLen > 0:
+      if t.kind == tyGenericParam and t.sonsLen > 0:
         result.add ": "
         var first = true
         for son in t.sons:
@@ -1528,10 +1528,9 @@ proc isCompileTimeOnly*(t: PType): bool {.inline.} =
 
 proc containsCompileTimeOnly*(t: PType): bool =
   if isCompileTimeOnly(t): return true
-  if t.sons != nil:
-    for i in 0 ..< t.sonsLen:
-      if t.sons[i] != nil and isCompileTimeOnly(t.sons[i]):
-        return true
+  for i in 0 ..< t.sonsLen:
+    if t.sons[i] != nil and isCompileTimeOnly(t.sons[i]):
+      return true
   return false
 
 type
diff --git a/lib/impure/re.nim b/lib/impure/re.nim
index 201c490f3..50a5441e8 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
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 db9a83755..5b0b6c6ee 100644
--- a/lib/packages/docutils/rstgen.nim
+++ b/lib/packages/docutils/rstgen.nim
@@ -397,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]) =
@@ -607,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:
@@ -656,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 da7c3473c..71a1600dc 100644
--- a/lib/pure/asyncnet.nim
+++ b/lib/pure/asyncnet.nim
@@ -655,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
@@ -670,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/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..b22016a3a 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".} =
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/unittest.nim b/lib/pure/unittest.nim
index aa07a4fa6..f4b89b2d0 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:
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 b92dd58d6..4b69a8067 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -3963,19 +3963,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
diff --git a/tests/async/tasync_misc.nim b/tests/async/tasync_misc.nim
index 695dcd98a..dbc2ea434 100644
--- a/tests/async/tasync_misc.nim
+++ b/tests/async/tasync_misc.nim
@@ -37,8 +37,7 @@ block: #8399
       case line[0]
       of '+', '-': @[]
       of '$': (let x = await bar(); @[""])
-      else:
-        nil
+      else: @[]
 
     doAssert(res == @[""])
 
diff --git a/tests/async/tasyncssl.nim b/tests/async/tasyncssl.nim
index 3dc131036..0607cf3c6 100644
--- a/tests/async/tasyncssl.nim
+++ b/tests/async/tasyncssl.nim
@@ -15,11 +15,11 @@ when defined(ssl):
   var clientCount = 0
 
   proc sendMessages(client: AsyncSocket) {.async.} =
-    for i in 0 .. <messagesToSend:
+    for i in 0 ..< messagesToSend:
       await send(client, "Message " & $i & "\c\L")
 
   proc launchSwarm(port: Port) {.async.} =
-    for i in 0 .. <swarmSize:
+    for i in 0 ..< swarmSize:
       var sock = newAsyncSocket()
       var clientContext = newContext(verifyMode = CVerifyNone)
       clientContext.wrapSocket(sock)