summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim16
-rw-r--r--compiler/ccgcalls.nim4
-rw-r--r--compiler/ccgexprs.nim7
-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/idents.nim37
-rw-r--r--compiler/jsgen.nim4
-rw-r--r--compiler/lineinfos.nim14
-rw-r--r--compiler/lookups.nim2
-rw-r--r--compiler/modulegraphs.nim54
-rw-r--r--compiler/msgs.nim8
-rw-r--r--compiler/options.nim33
-rw-r--r--compiler/parser.nim3
-rw-r--r--compiler/patterns.nim13
-rw-r--r--compiler/pragmas.nim2
-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/semtypes.nim2
-rw-r--r--compiler/semtypinst.nim4
-rw-r--r--compiler/sigmatch.nim22
-rw-r--r--compiler/types.nim9
-rw-r--r--compiler/vmdef.nim2
31 files changed, 175 insertions, 155 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index ef12e1184..e294eccc2 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -971,8 +971,8 @@ const
     tyFloat..tyFloat128, tyUInt..tyUInt64}
   ConstantDataTypes*: TTypeKinds = {tyArray, tySet,
                                     tyTuple, tySequence}
-  NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence,
-    tyProc, tyString, tyError}
+  NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr,
+    tyProc, tyError}
   ExportableSymKinds* = {skVar, skConst, skProc, skFunc, skMethod, skType,
     skIterator,
     skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias}
@@ -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 6803a9478..dd1c72ab6 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -65,9 +65,10 @@ 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)
-      #else:
-      result = genStringLiteral(p.module, n)
+      if n.strVal.len == 0 and optNilSeqs notin p.options:
+        result = genNilStringLiteral(p.module, n.info)
+      else:
+        result = genStringLiteral(p.module, n)
     else:
       if n.strVal.isNil: result = rope("NIM_NIL")
       else: result = makeCString(n.strVal)
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/idents.nim b/compiler/idents.nim
index 0a2f2d5cf..58800b73d 100644
--- a/compiler/idents.nim
+++ b/compiler/idents.nim
@@ -30,14 +30,7 @@ type
     wordCounter: int
     idAnon*, idDelegator*, emptyIdent*: PIdent
 
-when false:
-  var
-    legacy: IdentCache
-
-proc resetIdentCache*() =
-  when false:
-    for i in low(legacy.buckets)..high(legacy.buckets):
-      legacy.buckets[i] = nil
+proc resetIdentCache*() = discard
 
 proc cmpIgnoreStyle*(a, b: cstring, blen: int): int =
   if a[0] != b[0]: return 1
@@ -73,11 +66,9 @@ proc cmpExact(a, b: cstring, blen: int): int =
   if result == 0:
     if a[i] != '\0': result = 1
 
-{.this: self.}
-
-proc getIdent*(self: IdentCache; identifier: cstring, length: int, h: Hash): PIdent =
-  var idx = h and high(buckets)
-  result = buckets[idx]
+proc getIdent*(ic: IdentCache; identifier: cstring, length: int, h: Hash): PIdent =
+  var idx = h and high(ic.buckets)
+  result = ic.buckets[idx]
   var last: PIdent = nil
   var id = 0
   while result != nil:
@@ -85,8 +76,8 @@ proc getIdent*(self: IdentCache; identifier: cstring, length: int, h: Hash): PId
       if last != nil:
         # make access to last looked up identifier faster:
         last.next = result.next
-        result.next = buckets[idx]
-        buckets[idx] = result
+        result.next = ic.buckets[idx]
+        ic.buckets[idx] = result
       return
     elif cmpIgnoreStyle(cstring(result.s), identifier, length) == 0:
       assert((id == 0) or (id == result.id))
@@ -97,20 +88,20 @@ proc getIdent*(self: IdentCache; identifier: cstring, length: int, h: Hash): PId
   result.h = h
   result.s = newString(length)
   for i in countup(0, length - 1): result.s[i] = identifier[i]
-  result.next = buckets[idx]
-  buckets[idx] = result
+  result.next = ic.buckets[idx]
+  ic.buckets[idx] = result
   if id == 0:
-    inc(wordCounter)
-    result.id = -wordCounter
+    inc(ic.wordCounter)
+    result.id = -ic.wordCounter
   else:
     result.id = id
 
-proc getIdent*(self: IdentCache; identifier: string): PIdent =
-  result = getIdent(cstring(identifier), len(identifier),
+proc getIdent*(ic: IdentCache; identifier: string): PIdent =
+  result = getIdent(ic, cstring(identifier), len(identifier),
                     hashIgnoreStyle(identifier))
 
-proc getIdent*(self: IdentCache; identifier: string, h: Hash): PIdent =
-  result = getIdent(cstring(identifier), len(identifier), h)
+proc getIdent*(ic: IdentCache; identifier: string, h: Hash): PIdent =
+  result = getIdent(ic, cstring(identifier), len(identifier), h)
 
 proc newIdentCache*(): IdentCache =
   result = IdentCache()
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/modulegraphs.nim b/compiler/modulegraphs.nim
index 334cd1ae6..1eecc4176 100644
--- a/compiler/modulegraphs.nim
+++ b/compiler/modulegraphs.nim
@@ -65,10 +65,8 @@ type
 
 proc hash*(x: FileIndex): Hash {.borrow.}
 
-{.this: g.}
-
 proc stopCompile*(g: ModuleGraph): bool {.inline.} =
-  result = doStopCompile != nil and doStopCompile()
+  result = g.doStopCompile != nil and g.doStopCompile()
 
 proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym =
   result = newSym(skProc, getIdent(g.cache, name), nil, unknownLineInfo(), {})
@@ -98,44 +96,44 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
   result.cacheTables = initTable[string, BTree[string, PNode]]()
 
 proc resetAllModules*(g: ModuleGraph) =
-  initStrTable(packageSyms)
-  deps = initIntSet()
-  modules = @[]
-  importStack = @[]
-  inclToMod = initTable[FileIndex, FileIndex]()
-  usageSym = nil
-  owners = @[]
-  methods = @[]
-  initStrTable(compilerprocs)
-  initStrTable(exposed)
+  initStrTable(g.packageSyms)
+  g.deps = initIntSet()
+  g.modules = @[]
+  g.importStack = @[]
+  g.inclToMod = initTable[FileIndex, FileIndex]()
+  g.usageSym = nil
+  g.owners = @[]
+  g.methods = @[]
+  initStrTable(g.compilerprocs)
+  initStrTable(g.exposed)
 
 proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
-  if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len:
-    result = modules[fileIdx.int32]
+  if fileIdx.int32 >= 0 and fileIdx.int32 < g.modules.len:
+    result = g.modules[fileIdx.int32]
 
 proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b
 
 proc addDep*(g: ModuleGraph; m: PSym, dep: FileIndex) =
   assert m.position == m.info.fileIndex.int32
   addModuleDep(g.incr, g.config, m.info.fileIndex, dep, isIncludeFile = false)
-  if suggestMode:
-    deps.incl m.position.dependsOn(dep.int)
+  if g.suggestMode:
+    g.deps.incl m.position.dependsOn(dep.int)
     # we compute the transitive closure later when quering the graph lazily.
     # this improves efficiency quite a lot:
     #invalidTransitiveClosure = true
 
 proc addIncludeDep*(g: ModuleGraph; module, includeFile: FileIndex) =
   addModuleDep(g.incr, g.config, module, includeFile, isIncludeFile = true)
-  discard hasKeyOrPut(inclToMod, includeFile, module)
+  discard hasKeyOrPut(g.inclToMod, includeFile, module)
 
 proc parentModule*(g: ModuleGraph; fileIdx: FileIndex): FileIndex =
   ## returns 'fileIdx' if the file belonging to this index is
   ## directly used as a module or else the module that first
   ## references this include file.
-  if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len and modules[fileIdx.int32] != nil:
+  if fileIdx.int32 >= 0 and fileIdx.int32 < g.modules.len and g.modules[fileIdx.int32] != nil:
     result = fileIdx
   else:
-    result = inclToMod.getOrDefault(fileIdx)
+    result = g.inclToMod.getOrDefault(fileIdx)
 
 proc transitiveClosure(g: var IntSet; n: int) =
   # warshall's algorithm
@@ -147,22 +145,22 @@ proc transitiveClosure(g: var IntSet; n: int) =
             g.incl i.dependsOn(j)
 
 proc markDirty*(g: ModuleGraph; fileIdx: FileIndex) =
-  let m = getModule fileIdx
+  let m = g.getModule fileIdx
   if m != nil: incl m.flags, sfDirty
 
 proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) =
   # we need to mark its dependent modules D as dirty right away because after
   # nimsuggest is done with this module, the module's dirty flag will be
   # cleared but D still needs to be remembered as 'dirty'.
-  if invalidTransitiveClosure:
-    invalidTransitiveClosure = false
-    transitiveClosure(deps, modules.len)
+  if g.invalidTransitiveClosure:
+    g.invalidTransitiveClosure = false
+    transitiveClosure(g.deps, g.modules.len)
 
   # every module that *depends* on this file is also dirty:
-  for i in 0i32..<modules.len.int32:
-    let m = modules[i]
-    if m != nil and deps.contains(i.dependsOn(fileIdx.int)):
+  for i in 0i32..<g.modules.len.int32:
+    let m = g.modules[i]
+    if m != nil and g.deps.contains(i.dependsOn(fileIdx.int)):
       incl m.flags, sfDirty
 
 proc isDirty*(g: ModuleGraph; m: PSym): bool =
-  result = suggestMode and sfDirty in m.flags
+  result = g.suggestMode and sfDirty in m.flags
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 44519ea22..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**
@@ -482,7 +483,7 @@ include packagehandling
 
 proc getOsCacheDir(): string =
   when defined(posix):
-    result = string getEnv("XDG_CACHE_HOME", getHomeDir() / ".cache")
+    result = getEnv("XDG_CACHE_HOME", getHomeDir() / ".cache") / "nim"
   else:
     result = getHomeDir() / genSubDir
 
@@ -600,18 +601,22 @@ proc findModule*(conf: ConfigRef; modulename, currentModule: string): string =
 proc findProjectNimFile*(conf: ConfigRef; pkg: string): string =
   const extensions = [".nims", ".cfg", ".nimcfg", ".nimble"]
   var candidates: seq[string] = @[]
-  for k, f in os.walkDir(pkg, relative=true):
-    if k == pcFile and f != "config.nims":
-      let (_, name, ext) = splitFile(f)
-      if ext in extensions:
-        let x = changeFileExt(pkg / name, ".nim")
-        if fileExists(x):
-          candidates.add x
-  for c in candidates:
-    # nim-foo foo  or  foo  nfoo
-    if (pkg in c) or (c in pkg): return c
-  if candidates.len >= 1:
-    return candidates[0]
+  var dir = pkg
+  while true:
+    for k, f in os.walkDir(dir, relative=true):
+      if k == pcFile and f != "config.nims":
+        let (_, name, ext) = splitFile(f)
+        if ext in extensions:
+          let x = changeFileExt(dir / name, ".nim")
+          if fileExists(x):
+            candidates.add x
+    for c in candidates:
+      # nim-foo foo  or  foo  nfoo
+      if (pkg in c) or (c in pkg): return c
+    if candidates.len >= 1:
+      return candidates[0]
+    dir = parentDir(dir)
+    if dir == "": break
   return ""
 
 proc canonDynlibName(s: string): string =
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..ebb3a7c1d 100644
--- a/compiler/patterns.nim
+++ b/compiler/patterns.nim
@@ -21,14 +21,17 @@ type
     formals: int
     c: PContext
     subMatch: bool       # subnode matches are special
+    mappingIsFull: bool
   PPatternContext = var TPatternContext
 
 proc getLazy(c: PPatternContext, sym: PSym): PNode =
-  if not isNil(c.mapping):
+  if c.mappingIsFull:
     result = c.mapping[sym.position]
 
 proc putLazy(c: PPatternContext, sym: PSym, n: PNode) =
-  if isNil(c.mapping): newSeq(c.mapping, c.formals)
+  if not c.mappingIsFull:
+    newSeq(c.mapping, c.formals)
+    c.mappingIsFull = true
   c.mapping[sym.position] = n
 
 proc matches(c: PPatternContext, p, n: PNode): bool
@@ -209,7 +212,11 @@ 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 = @[]
+          c.mappingIsFull = false
+        else:
+          if not isNil(c.mapping): c.mapping = nil
         return false
     result = true
 
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index afe60e9dd..a067f2074 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -1066,8 +1066,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
       of wThis:
         if it.kind in nkPragmaCallKinds and it.len == 2:
           c.selfName = considerQuotedIdent(c, it[1])
+          message(c.config, n.info, warnDeprecated, "the '.this' pragma")
         elif it.kind == nkIdent or it.len == 1:
           c.selfName = getIdent(c.cache, "self")
+          message(c.config, n.info, warnDeprecated, "the '.this' pragma")
         else:
           localError(c.config, it.info, "'this' pragma is allowed to have zero or one arguments")
       of wNoRewrite:
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/semtypes.nim b/compiler/semtypes.nim
index 972c8c709..99f2cf20d 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -193,6 +193,8 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
         if region.skipTypes({tyGenericInst, tyAlias, tySink}).kind notin {
               tyError, tyObject}:
           message c.config, n[i].info, errGenerated, "region needs to be an object type"
+        else:
+          message(c.config, n.info, warnDeprecated, "region for pointer types")
         addSonSkipIntLit(result, region)
     addSonSkipIntLit(result, t)
     if tfPartial in result.flags:
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 c665aad7f..d779152d2 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/compiler/vmdef.nim b/compiler/vmdef.nim
index 50235c95f..1abd9ae4a 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -17,7 +17,7 @@ const
   byteExcess* = 128 # we use excess-K for immediates
   wordExcess* = 32768
 
-  MaxLoopIterations* = 1_000_000_000 # max iterations of all loops
+  MaxLoopIterations* = 3_000_000 # max iterations of all loops
 
 
 type