summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim10
-rw-r--r--compiler/ccgexprs.nim2
-rw-r--r--compiler/cgen.nim12
-rw-r--r--compiler/commands.nim2
-rw-r--r--compiler/docgen.nim10
-rw-r--r--compiler/filter_tmpl.nim6
-rw-r--r--compiler/jsgen.nim2
-rw-r--r--compiler/lexer.nim18
-rw-r--r--compiler/main.nim4
-rw-r--r--compiler/modulegraphs.nim40
-rw-r--r--compiler/modulepaths.nim2
-rw-r--r--compiler/modules.nim20
-rw-r--r--compiler/msgs.nim107
-rw-r--r--compiler/nimfix/pretty.nim10
-rw-r--r--compiler/nimfix/prettybase.nim16
-rw-r--r--compiler/parampatterns.nim3
-rw-r--r--compiler/parser.nim2
-rw-r--r--compiler/passes.nim24
-rw-r--r--compiler/pbraces.nim2
-rw-r--r--compiler/pragmas.nim2
-rw-r--r--compiler/reorder.nim20
-rw-r--r--compiler/rod.nim112
-rw-r--r--compiler/rodread.nim47
-rw-r--r--compiler/rodwrite.nim10
-rw-r--r--compiler/semdata.nim2
-rw-r--r--compiler/semstmts.nim8
-rw-r--r--compiler/suggest.nim4
-rw-r--r--compiler/syntaxes.nim4
-rw-r--r--compiler/vm.nim6
29 files changed, 196 insertions, 311 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index da7e828f2..4a0a9a20b 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -1042,9 +1042,9 @@ proc newNode*(kind: TNodeKind): PNode =
   new(result)
   result.kind = kind
   #result.info = UnknownLineInfo() inlined:
-  result.info.fileIndex = int32(-1)
+  result.info.fileIndex = InvalidFileIdx
   result.info.col = int16(-1)
-  result.info.line = int16(-1)
+  result.info.line = uint16(0)
   when defined(useNodeIds):
     result.id = gNodeId
     if result.id == nodeIdToDebug:
@@ -1116,13 +1116,13 @@ proc linkTo*(s: PSym, t: PType): PSym {.discardable.} =
   s.typ = t
   result = s
 
-template fileIdx*(c: PSym): int32 =
+template fileIdx*(c: PSym): FileIndex =
   # XXX: this should be used only on module symbols
-  c.position.int32
+  c.position.FileIndex
 
 template filename*(c: PSym): string =
   # XXX: this should be used only on module symbols
-  c.position.int32.toFilename
+  c.position.FileIndex.toFilename
 
 proc appendToModule*(m: PSym, n: PNode) =
   ## The compiler will use this internally to add nodes that will be
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 7e3c2632a..461a86298 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -2023,7 +2023,7 @@ template genStmtListExprImpl(exprOrStmt) {.dirty.} =
         let theMacro = it[0].sym
         add p.s(cpsStmts), initFrameNoDebug(p, frameName,
            makeCString theMacro.name.s,
-           theMacro.info.quotedFilename, it.info.line)
+           theMacro.info.quotedFilename, it.info.line.int)
     else:
       genStmts(p, it)
   if n.len > 0: exprOrStmt
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 4d3cabd3a..9e1f9349f 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -223,7 +223,7 @@ proc genLineDir(p: BProc, t: PNode) =
               line.rope, makeCString(toFilename(tt.info)))
   elif ({optLineTrace, optStackTrace} * p.options ==
       {optLineTrace, optStackTrace}) and
-      (p.prc == nil or sfPure notin p.prc.flags) and tt.info.fileIndex >= 0:
+      (p.prc == nil or sfPure notin p.prc.flags) and tt.info.fileIndex != InvalidFileIDX:
     if freshLineInfo(p, tt.info):
       linefmt(p, cpsStmts, "nimln_($1, $2);$n",
               line.rope, tt.info.quotedFilename)
@@ -678,7 +678,7 @@ proc generateHeaders(m: BModule) =
 
 proc openNamespaceNim(): Rope =
   result.add("namespace Nim {" & tnl)
-  
+
 proc closeNamespaceNim(): Rope =
   result.add("}" & tnl)
 
@@ -1090,7 +1090,7 @@ proc genMainProc(m: BModule) =
   appcg(m, m.s[cfsProcs], nimMain,
         [m.g.mainModInit, initStackBottomCall, rope(m.labels)])
   if optNoMain notin gGlobalOptions:
-    if useNimNamespace: 
+    if useNimNamespace:
       m.s[cfsProcs].add closeNamespaceNim() & "using namespace Nim;" & tnl
 
     appcg(m, m.s[cfsProcs], otherMain, [])
@@ -1202,7 +1202,7 @@ proc genModule(m: BModule, cfile: Cfile): Rope =
     add(result, genSectionStart(i))
     add(result, m.s[i])
     add(result, genSectionEnd(i))
-    if useNimNamespace and i == cfsHeaders: result.add openNamespaceNim()    
+    if useNimNamespace and i == cfsHeaders: result.add openNamespaceNim()
   add(result, m.s[cfsInitProc])
   if useNimNamespace: result.add closeNamespaceNim()
 
@@ -1301,7 +1301,7 @@ proc resetCgenModules*(g: BModuleList) =
   for m in cgenModules(g): resetModule(m)
 
 proc rawNewModule(g: BModuleList; module: PSym): BModule =
-  result = rawNewModule(g, module, module.position.int32.toFullPath)
+  result = rawNewModule(g, module, module.position.FileIndex.toFullPath)
 
 proc newModule(g: BModuleList; module: PSym): BModule =
   # we should create only one cgen module for each module sym
@@ -1311,7 +1311,7 @@ proc newModule(g: BModuleList; module: PSym): BModule =
 
   if (optDeadCodeElim in gGlobalOptions):
     if (sfDeadCodeElim in module.flags):
-      internalError("added pending module twice: " & module.filename)
+      internalError("added pending module twice: " & toFilename(FileIndex module.position))
 
 template injectG(config) {.dirty.} =
   if graph.backend == nil:
diff --git a/compiler/commands.nim b/compiler/commands.nim
index ec58706f3..e1dc1aacf 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -319,7 +319,7 @@ proc trackDirty(arg: string, info: TLineInfo) =
     localError(info, errInvalidNumber, a[2])
 
   let dirtyOriginalIdx = a[1].fileInfoIdx
-  if dirtyOriginalIdx >= 0:
+  if dirtyOriginalIdx.int32 >= 0:
     msgs.setDirtyFile(dirtyOriginalIdx, a[0])
 
   gTrackPos = newLineInfo(dirtyOriginalIdx, line, column)
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 74fb305ac..6f3dcde8b 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -544,7 +544,7 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
 
   initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
 
-  result = %{ "name": %name, "type": %($k), "line": %n.info.line,
+  result = %{ "name": %name, "type": %($k), "line": %n.info.line.int,
                  "col": %n.info.col}
   if comm != nil and comm != "":
     result["description"] = %comm
@@ -618,7 +618,7 @@ proc generateJson*(d: PDoc, n: PNode) =
   of nkCommentStmt:
     if n.comment != nil and startsWith(n.comment, "##"):
       let stripped = n.comment.substr(2).strip
-      d.add %{ "comment": %stripped, "line": %n.info.line,
+      d.add %{ "comment": %stripped, "line": %n.info.line.int,
                "col": %n.info.col }
   of nkProcDef:
     when useEffectSystem: documentRaises(n)
@@ -790,7 +790,7 @@ proc writeOutputJson*(d: PDoc, filename, outExt: string,
       discard "fixme: error report"
 
 proc commandDoc*() =
-  var ast = parseFile(gProjectMainIdx, newIdentCache())
+  var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache())
   if ast == nil: return
   var d = newDocumentor(gProjectFull, options.gConfigVars)
   d.hasToc = true
@@ -840,7 +840,7 @@ proc commandRst2TeX*() =
   commandRstAux(gProjectFull, TexExt)
 
 proc commandJson*() =
-  var ast = parseFile(gProjectMainIdx, newIdentCache())
+  var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache())
   if ast == nil: return
   var d = newDocumentor(gProjectFull, options.gConfigVars)
   d.hasToc = true
@@ -855,7 +855,7 @@ proc commandJson*() =
     writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
 
 proc commandTags*() =
-  var ast = parseFile(gProjectMainIdx, newIdentCache())
+  var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache())
   if ast == nil: return
   var d = newDocumentor(gProjectFull, options.gConfigVars)
   d.hasToc = true
diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim
index ca9a3a801..a1ba9113c 100644
--- a/compiler/filter_tmpl.nim
+++ b/compiler/filter_tmpl.nim
@@ -35,7 +35,7 @@ const
 proc newLine(p: var TTmplParser) =
   llStreamWrite(p.outp, repeat(')', p.emitPar))
   p.emitPar = 0
-  if p.info.line > int16(1): llStreamWrite(p.outp, "\n")
+  if p.info.line > uint16(1): llStreamWrite(p.outp, "\n")
   if p.pendingExprLine:
     llStreamWrite(p.outp, spaces(2))
     p.pendingExprLine = false
@@ -212,9 +212,9 @@ proc filterTmpl*(stdin: PLLStream, filename: string, call: PNode): PLLStream =
   p.x = newStringOfCap(120)
   # do not process the first line which contains the directive:
   if llStreamReadLine(p.inp, p.x):
-    p.info.line = p.info.line + int16(1)
+    p.info.line = p.info.line + 1'u16
   while llStreamReadLine(p.inp, p.x):
-    p.info.line = p.info.line + int16(1)
+    p.info.line = p.info.line + 1'u16
     parseLine(p)
   newLine(p)
   result = p.outp
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 475508946..2ae3426ab 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -2261,7 +2261,7 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
   var m = BModule(b)
   if sfMainModule in m.module.flags:
     let ext = "js"
-    let f = if globals.classes.len == 0: m.module.filename
+    let f = if globals.classes.len == 0: toFilename(FileIndex m.module.position)
             else: "nimsystem"
     let code = wholeCode(graph, m)
     let outfile =
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index a4a2615bd..0b1090bb1 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -133,7 +133,7 @@ type
 
   TErrorHandler* = proc (info: TLineInfo; msg: TMsgKind; arg: string)
   TLexer* = object of TBaseLexer
-    fileIdx*: int32
+    fileIdx*: FileIndex
     indentAhead*: int         # if > 0 an indendation has already been read
                               # this is needed because scanning comments
                               # needs so much look-ahead
@@ -222,7 +222,7 @@ proc fillToken(L: var TToken) =
     L.commentOffsetA = 0
     L.commentOffsetB = 0
 
-proc openLexer*(lex: var TLexer, fileIdx: int32, inputstream: PLLStream;
+proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream;
                  cache: IdentCache) =
   openBaseLexer(lex, inputstream)
   lex.fileIdx = fileidx
@@ -274,7 +274,7 @@ template tokenEnd(tok, pos) {.dirty.} =
   when defined(nimsuggest):
     let colB = getColNumber(L, pos)+1
     if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
-        L.lineNumber == gTrackPos.line and gIdeCmd in {ideSug, ideCon}:
+        L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}:
       L.cursor = CursorPosition.InToken
       gTrackPos.col = colA.int16
     colA = 0
@@ -285,9 +285,9 @@ template tokenEndIgnore(tok, pos) =
   when defined(nimsuggest):
     let colB = getColNumber(L, pos)
     if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
-        L.lineNumber == gTrackPos.line and gIdeCmd in {ideSug, ideCon}:
+        L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}:
       gTrackPos.fileIndex = trackPosInvalidFileIdx
-      gTrackPos.line = -1
+      gTrackPos.line = 0'u16
     colA = 0
   when defined(nimpretty):
     tok.offsetB = L.offsetBase + pos
@@ -299,7 +299,7 @@ template tokenEndPrevious(tok, pos) =
     # the cursor in a string literal or comment:
     let colB = getColNumber(L, pos)
     if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
-        L.lineNumber == gTrackPos.line and gIdeCmd in {ideSug, ideCon}:
+        L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}:
       L.cursor = CursorPosition.BeforeToken
       gTrackPos = L.previousToken
       gTrackPosAttached = true
@@ -1066,7 +1066,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
     when defined(nimsuggest):
       # we attach the cursor to the last *strong* token
       if tok.tokType notin weakTokens:
-        L.previousToken.line = tok.line.int16
+        L.previousToken.line = tok.line.uint16
         L.previousToken.col = tok.col.int16
 
   when defined(nimsuggest):
@@ -1118,7 +1118,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
         tok.tokType = tkParLe
         when defined(nimsuggest):
           if L.fileIdx == gTrackPos.fileIndex and tok.col < gTrackPos.col and
-                    tok.line == gTrackPos.line and gIdeCmd == ideCon:
+                    tok.line == gTrackPos.line.int and gIdeCmd == ideCon:
             gTrackPos.col = tok.col.int16
     of ')':
       tok.tokType = tkParRi
@@ -1139,7 +1139,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
     of '.':
       when defined(nimsuggest):
         if L.fileIdx == gTrackPos.fileIndex and tok.col+1 == gTrackPos.col and
-            tok.line == gTrackPos.line and gIdeCmd == ideSug:
+            tok.line == gTrackPos.line.int and gIdeCmd == ideSug:
           tok.tokType = tkDot
           L.cursor = CursorPosition.InToken
           gTrackPos.col = tok.col.int16
diff --git a/compiler/main.nim b/compiler/main.nim
index c928c81cd..401099fc3 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -35,7 +35,7 @@ proc writeDepsFile(g: ModuleGraph; project: string) =
   let f = open(changeFileExt(project, "deps"), fmWrite)
   for m in g.modules:
     if m != nil:
-      f.writeLine(toFullPath(m.position.int32))
+      f.writeLine(toFullPath(m.position.FileIndex))
   for k in g.inclToMod.keys:
     if g.getModule(k).isNil:  # don't repeat includes which are also modules
       f.writeLine(k.toFullPath)
@@ -265,7 +265,7 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
   of "parse":
     gCmd = cmdParse
     wantMainModule()
-    discard parseFile(gProjectMainIdx, cache)
+    discard parseFile(FileIndex gProjectMainIdx, cache)
   of "scan":
     gCmd = cmdScan
     wantMainModule()
diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim
index 2c59a9097..6c14a46e8 100644
--- a/compiler/modulegraphs.nim
+++ b/compiler/modulegraphs.nim
@@ -25,7 +25,7 @@
 ## - Its dependent module stays the same.
 ##
 
-import ast, intsets, tables, options, rod
+import ast, intsets, tables, options, rod, msgs, hashes
 
 type
   ModuleGraph* = ref object
@@ -34,10 +34,10 @@ type
     deps*: IntSet # the dependency graph or potentially its transitive closure.
     suggestMode*: bool # whether we are in nimsuggest mode or not.
     invalidTransitiveClosure: bool
-    inclToMod*: Table[int32, int32] # mapping of include file to the
-                                    # first module that included it
-    importStack*: seq[int32]  # The current import stack. Used for detecting recursive
-                              # module dependencies.
+    inclToMod*: Table[FileIndex, FileIndex] # mapping of include file to the
+                                            # first module that included it
+    importStack*: seq[FileIndex]  # The current import stack. Used for detecting recursive
+                                  # module dependencies.
     backend*: RootRef # minor hack so that a backend can extend this easily
     config*: ConfigRef
     doStopCompile*: proc(): bool {.closure.}
@@ -45,6 +45,8 @@ type
     owners*: seq[PSym]
     methods*: seq[tuple[methods: TSymSeq, dispatcher: PSym]]
 
+proc hash*(x: FileIndex): Hash {.borrow.}
+
 {.this: g.}
 
 proc stopCompile*(g: ModuleGraph): bool {.inline.} =
@@ -56,7 +58,7 @@ proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph =
   result.deps = initIntSet()
   result.modules = @[]
   result.importStack = @[]
-  result.inclToMod = initTable[int32, int32]()
+  result.inclToMod = initTable[FileIndex, FileIndex]()
   if config.isNil:
     result.config = newConfigRef()
   else:
@@ -69,35 +71,35 @@ proc resetAllModules*(g: ModuleGraph) =
   deps = initIntSet()
   modules = @[]
   importStack = @[]
-  inclToMod = initTable[int32, int32]()
+  inclToMod = initTable[FileIndex, FileIndex]()
   usageSym = nil
   owners = @[]
   methods = @[]
 
-proc getModule*(g: ModuleGraph; fileIdx: int32): PSym =
-  if fileIdx >= 0 and fileIdx < modules.len:
-    result = modules[fileIdx]
+proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
+  if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len:
+    result = modules[fileIdx.int32]
 
 proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b
 
-proc addDep*(g: ModuleGraph; m: PSym, dep: int32) =
-  assert m.position == m.info.fileIndex
+proc addDep*(g: ModuleGraph; m: PSym, dep: FileIndex) =
+  assert m.position == m.info.fileIndex.int32
   addModuleDep(m.info.fileIndex, dep, isIncludeFile = false)
   if suggestMode:
-    deps.incl m.position.dependsOn(dep)
+    deps.incl m.position.dependsOn(dep.int)
     # we compute the transitive closure later when quering the graph lazily.
     # this improve efficiency quite a lot:
     #invalidTransitiveClosure = true
 
-proc addIncludeDep*(g: ModuleGraph; module, includeFile: int32) =
+proc addIncludeDep*(g: ModuleGraph; module, includeFile: FileIndex) =
   addModuleDep(module, includeFile, isIncludeFile = true)
   discard hasKeyOrPut(inclToMod, includeFile, module)
 
-proc parentModule*(g: ModuleGraph; fileIdx: int32): int32 =
+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 >= 0 and fileIdx < modules.len and modules[fileIdx] != nil:
+  if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len and modules[fileIdx.int32] != nil:
     result = fileIdx
   else:
     result = inclToMod.getOrDefault(fileIdx)
@@ -111,11 +113,11 @@ proc transitiveClosure(g: var IntSet; n: int) =
           if g.contains(i.dependsOn(k)) and g.contains(k.dependsOn(j)):
             g.incl i.dependsOn(j)
 
-proc markDirty*(g: ModuleGraph; fileIdx: int32) =
+proc markDirty*(g: ModuleGraph; fileIdx: FileIndex) =
   let m = getModule fileIdx
   if m != nil: incl m.flags, sfDirty
 
-proc markClientsDirty*(g: ModuleGraph; fileIdx: int32) =
+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'.
@@ -126,7 +128,7 @@ proc markClientsDirty*(g: ModuleGraph; fileIdx: int32) =
   # 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)):
+    if m != nil and deps.contains(i.dependsOn(fileIdx.int)):
       incl m.flags, sfDirty
 
 proc isDirty*(g: ModuleGraph; m: PSym): bool =
diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim
index 878c22cf8..1318b67a7 100644
--- a/compiler/modulepaths.nim
+++ b/compiler/modulepaths.nim
@@ -174,7 +174,7 @@ proc getModuleName*(n: PNode): string =
     localError(n.info, errGenerated, "invalid module name: '$1'" % n.renderTree)
     result = ""
 
-proc checkModuleName*(n: PNode; doLocalError=true): int32 =
+proc checkModuleName*(n: PNode; doLocalError=true): FileIndex =
   # This returns the full canonical path for a given module import
   let modulename = n.getModuleName
   let fullPath = findModule(modulename, n.info.toFullPath)
diff --git a/compiler/modules.nim b/compiler/modules.nim
index a3be5a518..52a6f2fdd 100644
--- a/compiler/modules.nim
+++ b/compiler/modules.nim
@@ -121,7 +121,7 @@ when false:
 proc resetSystemArtifacts*() =
   magicsys.resetSysTypes()
 
-proc newModule(graph: ModuleGraph; fileIdx: int32): PSym =
+proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
   # We cannot call ``newSym`` here, because we have to circumvent the ID
   # mechanism, which we do in order to assign each module a persistent ID.
   new(result)
@@ -144,9 +144,9 @@ proc newModule(graph: ModuleGraph; fileIdx: int32): PSym =
     graph.packageSyms.strTableAdd(packSym)
 
   result.owner = packSym
-  result.position = fileIdx
+  result.position = int fileIdx
 
-  growCache graph.modules, fileIdx
+  growCache graph.modules, int fileIdx
   graph.modules[result.position] = result
 
   incl(result.flags, sfUsed)
@@ -158,7 +158,7 @@ proc newModule(graph: ModuleGraph; fileIdx: int32): PSym =
   # strTableIncl() for error corrections:
   discard strTableIncl(packSym.tab, result)
 
-proc compileModule*(graph: ModuleGraph; fileIdx: int32; cache: IdentCache, flags: TSymFlags): PSym =
+proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; cache: IdentCache, flags: TSymFlags): PSym =
   result = graph.getModule(fileIdx)
   if result == nil:
     #growCache gMemCacheData, fileIdx
@@ -199,7 +199,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: int32; cache: IdentCache, flags
       else:
         result = gCompiledModules[fileIdx]
 
-proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: int32;
+proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
                    cache: IdentCache): PSym {.procvar.} =
   # this is called by the semantic checking phase
   result = compileModule(graph, fileIdx, cache, {})
@@ -210,11 +210,11 @@ proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: int32;
   gNotes = if s.owner.id == gMainPackageId: gMainPackageNotes
            else: ForeignPackageNotes
 
-proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: int32;
+proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
                     cache: IdentCache): PNode {.procvar.} =
   result = syntaxes.parseFile(fileIdx, cache)
   graph.addDep(s, fileIdx)
-  graph.addIncludeDep(s.position.int32, fileIdx)
+  graph.addIncludeDep(s.position.FileIndex, fileIdx)
 
 proc compileSystemModule*(graph: ModuleGraph; cache: IdentCache) =
   if magicsys.systemModule == nil:
@@ -224,16 +224,16 @@ proc compileSystemModule*(graph: ModuleGraph; cache: IdentCache) =
 proc wantMainModule* =
   if gProjectFull.len == 0:
     fatal(gCmdLineInfo, errCommandExpectsFilename)
-  gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
+  gProjectMainIdx = int32 addFileExt(gProjectFull, NimExt).fileInfoIdx
 
 passes.gIncludeFile = includeModule
 passes.gImportModule = importModule
 
 proc compileProject*(graph: ModuleGraph; cache: IdentCache;
-                     projectFileIdx = -1'i32) =
+                     projectFileIdx = InvalidFileIDX) =
   wantMainModule()
   let systemFileIdx = fileInfoIdx(options.libpath / "system.nim")
-  let projectFile = if projectFileIdx < 0: gProjectMainIdx else: projectFileIdx
+  let projectFile = if projectFileIdx == InvalidFileIDX: FileIndex(gProjectMainIdx) else: projectFileIdx
   graph.importStack.add projectFile
   if projectFile == systemFileIdx:
     discard graph.compileModule(projectFile, cache, {sfMainModule, sfSystemModule})
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 35be5e772..06f333cef 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -499,14 +499,15 @@ type
     hash*: string              # the checksum of the file
     when defined(nimpretty):
       fullContent*: string
-  FileIndex* = int32           # XXX will make this 'distinct' later
+  FileIndex* = distinct int32
   TLineInfo* = object          # This is designed to be as small as possible,
                                # because it is used
                                # in syntax nodes. We save space here by using
                                # two int16 and an int32.
                                # On 64 bit and on 32 bit systems this is
                                # only 8 bytes.
-    line*, col*: int16
+    line*: uint16
+    col*: int16
     fileIndex*: FileIndex
     when defined(nimpretty):
       offsetA*, offsetB*: int
@@ -521,6 +522,8 @@ type
   ERecoverableError* = object of ValueError
   ESuggestDone* = object of Exception
 
+proc `==`*(a, b: FileIndex): bool {.borrow.}
+
 const
   NotesVerbosity*: array[0..3, TNoteKinds] = [
     {low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
@@ -545,14 +548,14 @@ const
     {low(TNoteKind)..high(TNoteKind)}]
 
 const
-  InvalidFileIDX* = int32(-1)
+  InvalidFileIDX* = FileIndex(-1)
 
 var
   ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic,
     hintQuitCalled, hintExecuting}
-  filenameToIndexTbl = initTable[string, int32]()
+  filenameToIndexTbl = initTable[string, FileIndex]()
   fileInfos*: seq[TFileInfo] = @[]
-  systemFileIdx*: int32
+  systemFileIdx*: FileIndex
 
 proc toCChar*(c: char): string =
   case c
@@ -598,7 +601,7 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo =
 
 when defined(nimpretty):
   proc fileSection*(fid: FileIndex; a, b: int): string =
-    substr(fileInfos[fid].fullContent, a, b)
+    substr(fileInfos[fid.int].fullContent, a, b)
 
 proc fileInfoKnown*(filename: string): bool =
   var
@@ -609,7 +612,7 @@ proc fileInfoKnown*(filename: string): bool =
     canon = filename
   result = filenameToIndexTbl.hasKey(canon)
 
-proc fileInfoIdx*(filename: string; isKnownFile: var bool): int32 =
+proc fileInfoIdx*(filename: string; isKnownFile: var bool): FileIndex =
   var
     canon: string
     pseudoPath = false
@@ -627,28 +630,28 @@ proc fileInfoIdx*(filename: string; isKnownFile: var bool): int32 =
     result = filenameToIndexTbl[canon]
   else:
     isKnownFile = false
-    result = fileInfos.len.int32
+    result = fileInfos.len.FileIndex
     fileInfos.add(newFileInfo(canon, if pseudoPath: filename
                                      else: canon.shortenDir))
     filenameToIndexTbl[canon] = result
 
-proc fileInfoIdx*(filename: string): int32 =
+proc fileInfoIdx*(filename: string): FileIndex =
   var dummy: bool
   result = fileInfoIdx(filename, dummy)
 
-proc newLineInfo*(fileInfoIdx: int32, line, col: int): TLineInfo =
+proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
   result.fileIndex = fileInfoIdx
-  result.line = int16(line)
+  result.line = uint16(line)
   result.col = int16(col)
 
 proc newLineInfo*(filename: string, line, col: int): TLineInfo {.inline.} =
   result = newLineInfo(filename.fileInfoIdx, line, col)
 
 fileInfos.add(newFileInfo("", "command line"))
-var gCmdLineInfo* = newLineInfo(int32(0), 1, 1)
+var gCmdLineInfo* = newLineInfo(FileIndex(0), 1, 1)
 
 fileInfos.add(newFileInfo("", "compilation artifact"))
-var gCodegenLineInfo* = newLineInfo(int32(1), 1, 1)
+var gCodegenLineInfo* = newLineInfo(FileIndex(1), 1, 1)
 
 proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
   raise newException(ERecoverableError, msg)
@@ -664,9 +667,9 @@ var
   gMainPackageNotes*: TNoteKinds = NotesVerbosity[1]
 
 proc unknownLineInfo*(): TLineInfo =
-  result.line = int16(-1)
+  result.line = uint16(0)
   result.col = int16(-1)
-  result.fileIndex = -1
+  result.fileIndex = InvalidFileIDX
 
 type
   Severity* {.pure.} = enum ## VS Code only supports these three
@@ -728,32 +731,32 @@ proc getInfoContext*(index: int): TLineInfo =
   if i >=% L: result = unknownLineInfo()
   else: result = msgContext[i]
 
-template toFilename*(fileIdx: int32): string =
-  (if fileIdx < 0: "???" else: fileInfos[fileIdx].projPath)
+template toFilename*(fileIdx: FileIndex): string =
+  (if fileIdx.int32 < 0: "???" else: fileInfos[fileIdx.int32].projPath)
 
-proc toFullPath*(fileIdx: int32): string =
-  if fileIdx < 0: result = "???"
-  else: result = fileInfos[fileIdx].fullPath
+proc toFullPath*(fileIdx: FileIndex): string =
+  if fileIdx.int32 < 0: result = "???"
+  else: result = fileInfos[fileIdx.int32].fullPath
 
-proc setDirtyFile*(fileIdx: int32; filename: string) =
-  assert fileIdx >= 0
-  fileInfos[fileIdx].dirtyFile = filename
+proc setDirtyFile*(fileIdx: FileIndex; filename: string) =
+  assert fileIdx.int32 >= 0
+  fileInfos[fileIdx.int32].dirtyFile = filename
 
-proc setHash*(fileIdx: int32; hash: string) =
-  assert fileIdx >= 0
-  shallowCopy(fileInfos[fileIdx].hash, hash)
+proc setHash*(fileIdx: FileIndex; hash: string) =
+  assert fileIdx.int32 >= 0
+  shallowCopy(fileInfos[fileIdx.int32].hash, hash)
 
-proc getHash*(fileIdx: int32): string =
-  assert fileIdx >= 0
-  shallowCopy(result, fileInfos[fileIdx].hash)
+proc getHash*(fileIdx: FileIndex): string =
+  assert fileIdx.int32 >= 0
+  shallowCopy(result, fileInfos[fileIdx.int32].hash)
 
-proc toFullPathConsiderDirty*(fileIdx: int32): string =
-  if fileIdx < 0:
+proc toFullPathConsiderDirty*(fileIdx: FileIndex): string =
+  if fileIdx.int32 < 0:
     result = "???"
-  elif not fileInfos[fileIdx].dirtyFile.isNil:
-    result = fileInfos[fileIdx].dirtyFile
+  elif not fileInfos[fileIdx.int32].dirtyFile.isNil:
+    result = fileInfos[fileIdx.int32].dirtyFile
   else:
-    result = fileInfos[fileIdx].fullPath
+    result = fileInfos[fileIdx.int32].fullPath
 
 template toFilename*(info: TLineInfo): string =
   info.fileIndex.toFilename
@@ -762,15 +765,15 @@ template toFullPath*(info: TLineInfo): string =
   info.fileIndex.toFullPath
 
 proc toMsgFilename*(info: TLineInfo): string =
-  if info.fileIndex < 0:
+  if info.fileIndex.int32 < 0:
     result = "???"
   elif gListFullPaths:
-    result = fileInfos[info.fileIndex].fullPath
+    result = fileInfos[info.fileIndex.int32].fullPath
   else:
-    result = fileInfos[info.fileIndex].projPath
+    result = fileInfos[info.fileIndex.int32].projPath
 
 proc toLinenumber*(info: TLineInfo): int {.inline.} =
-  result = info.line
+  result = int info.line
 
 proc toColumn*(info: TLineInfo): int {.inline.} =
   result = info.col
@@ -787,7 +790,7 @@ proc `??`* (info: TLineInfo, filename: string): bool =
   # only for debugging purposes
   result = filename in info.toFilename
 
-const trackPosInvalidFileIdx* = -2 # special marker so that no suggestions
+const trackPosInvalidFileIdx* = FileIndex(-2) # special marker so that no suggestions
                                    # are produced within comments and string literals
 var gTrackPos*: TLineInfo
 var gTrackPosAttached*: bool ## whether the tracking position was attached to some
@@ -926,7 +929,7 @@ proc writeContext(lastinfo: TLineInfo) =
       else:
         styledMsgWriteln(styleBright,
                          PosFormat % [toMsgFilename(msgContext[i]),
-                                      coordToStr(msgContext[i].line),
+                                      coordToStr(msgContext[i].line.int),
                                       coordToStr(msgContext[i].col+1)],
                          resetStyle,
                          getMessageStr(errInstantiationFrom, ""))
@@ -994,7 +997,7 @@ proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
               of warnMin..warnMax: WarningTitle
               of hintMin..hintMax: HintTitle
               else: ErrorTitle
-  result = PosFormat % [toMsgFilename(info), coordToStr(info.line),
+  result = PosFormat % [toMsgFilename(info), coordToStr(info.line.int),
                         coordToStr(info.col+1)] &
            title &
            getMessageStr(msg, arg)
@@ -1035,7 +1038,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
   # NOTE: currently line info line numbers start with 1,
   # but column numbers start with 0, however most editors expect
   # first column to be 1, so we need to +1 here
-  let x = PosFormat % [toMsgFilename(info), coordToStr(info.line),
+  let x = PosFormat % [toMsgFilename(info), coordToStr(info.line.int),
                        coordToStr(info.col+1)]
   let s = getMessageStr(msg, arg)
 
@@ -1093,30 +1096,30 @@ template assertNotNil*(e): untyped =
 template internalAssert*(e: bool) =
   if not e: internalError($instantiationInfo())
 
-proc addSourceLine*(fileIdx: int32, line: string) =
-  fileInfos[fileIdx].lines.add line.rope
+proc addSourceLine*(fileIdx: FileIndex, line: string) =
+  fileInfos[fileIdx.int32].lines.add line.rope
 
 proc sourceLine*(i: TLineInfo): Rope =
-  if i.fileIndex < 0: return nil
+  if i.fileIndex.int32 < 0: return nil
 
-  if not optPreserveOrigSource and fileInfos[i.fileIndex].lines.len == 0:
+  if not optPreserveOrigSource and fileInfos[i.fileIndex.int32].lines.len == 0:
     try:
       for line in lines(i.toFullPath):
         addSourceLine i.fileIndex, line.string
     except IOError:
       discard
-  internalAssert i.fileIndex < fileInfos.len
+  internalAssert i.fileIndex.int32 < fileInfos.len
   # can happen if the error points to EOF:
-  if i.line > fileInfos[i.fileIndex].lines.len: return nil
+  if i.line.int > fileInfos[i.fileIndex.int32].lines.len: return nil
 
-  result = fileInfos[i.fileIndex].lines[i.line-1]
+  result = fileInfos[i.fileIndex.int32].lines[i.line.int-1]
 
 proc quotedFilename*(i: TLineInfo): Rope =
-  internalAssert i.fileIndex >= 0
+  internalAssert i.fileIndex.int32 >= 0
   if optExcessiveStackTrace in gGlobalOptions:
-    result = fileInfos[i.fileIndex].quotedFullName
+    result = fileInfos[i.fileIndex.int32].quotedFullName
   else:
-    result = fileInfos[i.fileIndex].quotedName
+    result = fileInfos[i.fileIndex.int32].quotedName
 
 ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) =
   case err
diff --git a/compiler/nimfix/pretty.nim b/compiler/nimfix/pretty.nim
index 55603f4cd..4627264dc 100644
--- a/compiler/nimfix/pretty.nim
+++ b/compiler/nimfix/pretty.nim
@@ -28,7 +28,7 @@ proc overwriteFiles*() =
   let doStrip = options.getConfigVar("pretty.strip").normalize == "on"
   for i in 0 .. high(gSourceFiles):
     if gSourceFiles[i].dirty and not gSourceFiles[i].isNimfixFile and
-        (not gOnlyMainfile or gSourceFiles[i].fileIdx == gProjectMainIdx):
+        (not gOnlyMainfile or gSourceFiles[i].fileIdx == gProjectMainIdx.FileIndex):
       let newFile = if gOverWrite: gSourceFiles[i].fullpath
                     else: gSourceFiles[i].fullpath.changeFileExt(".pretty.nim")
       try:
@@ -95,7 +95,7 @@ proc beautifyName(s: string, k: TSymKind): string =
 proc replaceInFile(info: TLineInfo; newName: string) =
   loadFile(info)
 
-  let line = gSourceFiles[info.fileIndex].lines[info.line-1]
+  let line = gSourceFiles[info.fileIndex.int].lines[info.line.int-1]
   var first = min(info.col.int, line.len)
   if first < 0: return
   #inc first, skipIgnoreCase(line, "proc ", first)
@@ -107,8 +107,8 @@ proc replaceInFile(info: TLineInfo; newName: string) =
   if differ(line, first, last, newName):
     # last-first+1 != newName.len or
     var x = line.substr(0, first-1) & newName & line.substr(last+1)
-    system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
-    gSourceFiles[info.fileIndex].dirty = true
+    system.shallowCopy(gSourceFiles[info.fileIndex.int].lines[info.line.int-1], x)
+    gSourceFiles[info.fileIndex.int].dirty = true
 
 proc checkStyle(info: TLineInfo, s: string, k: TSymKind; sym: PSym) =
   let beau = beautifyName(s, k)
@@ -136,7 +136,7 @@ template styleCheckDef*(s: PSym) =
   styleCheckDef(s.info, s, s.kind)
 
 proc styleCheckUseImpl(info: TLineInfo; s: PSym) =
-  if info.fileIndex < 0: return
+  if info.fileIndex.int < 0: return
   # we simply convert it to what it looks like in the definition
   # for consistency
 
diff --git a/compiler/nimfix/prettybase.nim b/compiler/nimfix/prettybase.nim
index f1d24183b..ecb4b0093 100644
--- a/compiler/nimfix/prettybase.nim
+++ b/compiler/nimfix/prettybase.nim
@@ -16,13 +16,13 @@ type
     lines*: seq[string]
     dirty*, isNimfixFile*: bool
     fullpath*, newline*: string
-    fileIdx*: int32
+    fileIdx*: FileIndex
 
 var
   gSourceFiles*: seq[TSourceFile] = @[]
 
 proc loadFile*(info: TLineInfo) =
-  let i = info.fileIndex
+  let i = info.fileIndex.int
   if i >= gSourceFiles.len:
     gSourceFiles.setLen(i+1)
   if gSourceFiles[i].lines.isNil:
@@ -64,7 +64,7 @@ proc differ*(line: string, a, b: int, x: string): bool =
 proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) =
   loadFile(info)
 
-  let line = gSourceFiles[info.fileIndex].lines[info.line-1]
+  let line = gSourceFiles[info.fileIndex.int32].lines[info.line.int-1]
   var first = min(info.col.int, line.len)
   if first < 0: return
   #inc first, skipIgnoreCase(line, "proc ", first)
@@ -75,8 +75,8 @@ proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) =
   let last = first+identLen(line, first)-1
   if cmpIgnoreStyle(line[first..last], oldSym.s) == 0:
     var x = line.substr(0, first-1) & newSym.s & line.substr(last+1)
-    system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
-    gSourceFiles[info.fileIndex].dirty = true
+    system.shallowCopy(gSourceFiles[info.fileIndex.int32].lines[info.line.int-1], x)
+    gSourceFiles[info.fileIndex.int32].dirty = true
     #if newSym.s == "File": writeStackTrace()
 
 proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PSym) =
@@ -85,10 +85,10 @@ proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PSym) =
 proc replaceComment*(info: TLineInfo) =
   loadFile(info)
 
-  let line = gSourceFiles[info.fileIndex].lines[info.line-1]
+  let line = gSourceFiles[info.fileIndex.int32].lines[info.line.int-1]
   var first = info.col.int
   if line[first] != '#': inc first
 
   var x = line.substr(0, first-1) & "discard " & line.substr(first+1).escape
-  system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
-  gSourceFiles[info.fileIndex].dirty = true
+  system.shallowCopy(gSourceFiles[info.fileIndex.int32].lines[info.line.int-1], x)
+  gSourceFiles[info.fileIndex.int32].dirty = true
diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim
index 8540f1b32..02c48c16d 100644
--- a/compiler/parampatterns.nim
+++ b/compiler/parampatterns.nim
@@ -235,7 +235,8 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
       result = arLValue
     else:
       result = isAssignable(owner, n.sons[0], isUnsafeAddr)
-    if result != arNone and sfDiscriminant in n.sons[1].sym.flags:
+    if result != arNone and n[1].kind == nkSym and
+        sfDiscriminant in n[1].sym.flags:
       result = arDiscriminant
   of nkBracketExpr:
     if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind in
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 3bf75c6f7..ac0a57770 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -83,7 +83,7 @@ proc getTok(p: var TParser) =
   rawGetTok(p.lex, p.tok)
   p.hasProgress = true
 
-proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream,
+proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream,
                  cache: IdentCache;
                  strongSpaces=false) =
   ## Open a parser, using the given arguments to set up its internal state.
diff --git a/compiler/passes.nim b/compiler/passes.nim
index f079100ea..d7c181676 100644
--- a/compiler/passes.nim
+++ b/compiler/passes.nim
@@ -52,8 +52,8 @@ proc makePass*(open: TPassOpen = nil,
 
 # the semantic checker needs these:
 var
-  gImportModule*: proc (graph: ModuleGraph; m: PSym, fileIdx: int32; cache: IdentCache): PSym {.nimcall.}
-  gIncludeFile*: proc (graph: ModuleGraph; m: PSym, fileIdx: int32; cache: IdentCache): PNode {.nimcall.}
+  gImportModule*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex; cache: IdentCache): PSym {.nimcall.}
+  gIncludeFile*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex; cache: IdentCache): PNode {.nimcall.}
 
 # implementation
 
@@ -63,20 +63,6 @@ proc skipCodegen*(n: PNode): bool {.inline.} =
   # error count instead.
   result = msgs.gErrorCounter > 0
 
-proc astNeeded*(s: PSym): bool =
-  # The ``rodwrite`` module uses this to determine if the body of a proc
-  # needs to be stored. The passes manager frees s.sons[codePos] when
-  # appropriate to free the procedure body's memory. This is important
-  # to keep memory usage down.
-  if (s.kind in {skMethod, skProc, skFunc}) and
-      ({sfCompilerProc, sfCompileTime} * s.flags == {}) and
-      (s.typ.callConv != ccInline) and
-      (s.ast.sons[genericParamsPos].kind == nkEmpty):
-    result = false
-    # XXX this doesn't really make sense with excessive CTFE
-  else:
-    result = true
-
 const
   maxPasses = 10
 
@@ -153,7 +139,7 @@ proc closePassesCached(graph: ModuleGraph; a: var TPassContextArray) =
       m = gPasses[i].close(graph, a[i], m)
     a[i] = nil                # free the memory here
 
-proc resolveMod(module, relativeTo: string): int32 =
+proc resolveMod(module, relativeTo: string): FileIndex =
   let fullPath = findModule(module, relativeTo)
   if fullPath.len == 0:
     result = InvalidFileIDX
@@ -166,7 +152,7 @@ proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
   let relativeTo = m.info.toFullPath
   for module in items(implicits):
     # implicit imports should not lead to a module importing itself
-    if m.position != resolveMod(module, relativeTo):
+    if m.position != resolveMod(module, relativeTo).int32:
       var importStmt = newNodeI(nodeKind, gCmdLineInfo)
       var str = newStrNode(nkStrLit, module)
       str.info = gCmdLineInfo
@@ -180,7 +166,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
     p: TParsers
     a: TPassContextArray
     s: PLLStream
-    fileIdx = module.fileIdx
+    fileIdx = FileIndex module.fileIdx
   if module.id < 0:
     # new module caching mechanism:
     for i in 0..<gPassesLen:
diff --git a/compiler/pbraces.nim b/compiler/pbraces.nim
index eba6f0b62..fe438d58b 100644
--- a/compiler/pbraces.nim
+++ b/compiler/pbraces.nim
@@ -19,7 +19,7 @@ proc getTok(p: var TParser) =
   ## `tok` member.
   rawGetTok(p.lex, p.tok)
 
-proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream;
+proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream;
                  cache: IdentCache) =
   ## Open a parser, using the given arguments to set up its internal state.
   ##
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index bb7801f6f..cb11564a4 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -543,7 +543,7 @@ proc pragmaLine(c: PContext, n: PNode) =
       else:
         # XXX this produces weird paths which are not properly resolved:
         n.info.fileIndex = msgs.fileInfoIdx(x.strVal)
-        n.info.line = int16(y.intVal)
+        n.info.line = uint16(y.intVal)
     else:
       localError(n.info, errXExpected, "tuple")
   else:
diff --git a/compiler/reorder.nim b/compiler/reorder.nim
index cde5b3a9f..878e3b11e 100644
--- a/compiler/reorder.nim
+++ b/compiler/reorder.nim
@@ -1,6 +1,6 @@
 
-import 
-  intsets, ast, idents, algorithm, renderer, parser, ospaths, strutils, 
+import
+  intsets, ast, idents, algorithm, renderer, parser, ospaths, strutils,
   sequtils, msgs, modulegraphs, syntaxes, options, modulepaths, tables
 
 type
@@ -135,13 +135,13 @@ proc hasIncludes(n:PNode): bool =
     if a.kind == nkIncludeStmt:
       return true
 
-proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: int32;
+proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
                     cache: IdentCache): PNode {.procvar.} =
   result = syntaxes.parseFile(fileIdx, cache)
   graph.addDep(s, fileIdx)
-  graph.addIncludeDep(s.position.int32, fileIdx)
+  graph.addIncludeDep(FileIndex s.position, fileIdx)
 
-proc expandIncludes(graph: ModuleGraph, module: PSym, n: PNode, 
+proc expandIncludes(graph: ModuleGraph, module: PSym, n: PNode,
                     modulePath: string, includedFiles: var IntSet,
                     cache: IdentCache): PNode =
   # Parses includes and injects them in the current tree
@@ -153,13 +153,13 @@ proc expandIncludes(graph: ModuleGraph, module: PSym, n: PNode,
       for i in 0..<a.len:
         var f = checkModuleName(a.sons[i])
         if f != InvalidFileIDX:
-          if containsOrIncl(includedFiles, f):
+          if containsOrIncl(includedFiles, f.int):
             localError(a.info, errRecursiveDependencyX, f.toFilename)
           else:
             let nn = includeModule(graph, module, f, cache)
-            let nnn = expandIncludes(graph, module, nn, modulePath, 
+            let nnn = expandIncludes(graph, module, nn, modulePath,
                                       includedFiles, cache)
-            excl(includedFiles, f)
+            excl(includedFiles, f.int)
             for b in nnn:
               result.add b
     else:
@@ -429,8 +429,8 @@ proc reorder*(graph: ModuleGraph, n: PNode, module: PSym, cache: IdentCache): PN
   if n.hasForbiddenPragma:
     return n
   var includedFiles = initIntSet()
-  let mpath = module.fileIdx.toFullPath
-  let n = expandIncludes(graph, module, n, mpath, 
+  let mpath = module.fileIdx.FileIndex.toFullPath
+  let n = expandIncludes(graph, module, n, mpath,
                           includedFiles, cache).splitSections
   result = newNodeI(nkStmtList, n.info)
   var deps = newSeq[(IntSet, IntSet)](n.len)
diff --git a/compiler/rod.nim b/compiler/rod.nim
index bc2f3931e..c144f15ef 100644
--- a/compiler/rod.nim
+++ b/compiler/rod.nim
@@ -9,124 +9,18 @@
 
 ## This module implements the canonalization for the various caching mechanisms.
 
-import ast, idgen
+import ast, idgen, msgs
 
 when not defined(nimSymbolfiles):
   template setupModuleCache* = discard
   template storeNode*(module: PSym; n: PNode) = discard
   template loadNode*(module: PSym; index: var int): PNode = PNode(nil)
 
-  template getModuleId*(fileIdx: int32; fullpath: string): int = getID()
+  template getModuleId*(fileIdx: FileIndex; fullpath: string): int = getID()
 
-  template addModuleDep*(module, fileIdx: int32; isIncludeFile: bool) = discard
+  template addModuleDep*(module, fileIdx: FileIndex; isIncludeFile: bool) = discard
 
   template storeRemaining*(module: PSym) = discard
 
 else:
   include rodimpl
-
-when false:
-  type
-    BlobWriter* = object
-      buf: string
-      pos: int
-
-    SerializationAction = enum acRead, acWrite
-
-  # Varint implementation inspired by SQLite.
-  proc rdVaruint64(z: ptr UncheckedArray[byte]; n: int; pResult: var uint64): int =
-    if z[0] <= 240:
-      pResult = z[0]
-      return 1
-    if z[0] <= 248:
-      if n < 2: return 0
-      pResult = (z[0] - 241) * 256 + z[1] + 240
-      return 2
-    if n < z[0]-246: return 0
-    if z[0] == 249:
-      pResult = 2288 + 256*z[1] + z[2]
-      return 3
-    if z[0] == 250:
-      pResult = (z[1] shl 16u64) + (z[2] shl 8u64) + z[3]
-      return 4
-    let x = (z[1] shl 24) + (z[2] shl 16) + (z[3] shl 8) + z[4]
-    if z[0] == 251:
-      pResult = x
-      return 5
-    if z[0] == 252:
-      pResult = (((uint64)x) shl 8) + z[5]
-      return 6
-    if z[0] == 253:
-      pResult = (((uint64)x) shl 16) + (z[5] shl 8) + z[6]
-      return 7
-    if z[0] == 254:
-      pResult = (((uint64)x) shl 24) + (z[5] shl 16) + (z[6] shl 8) + z[7]
-      return 8
-    pResult = (((uint64)x) shl 32) +
-                (0xffffffff & ((z[5] shl 24) + (z[6] shl 16) + (z[7] shl 8) + z[8]))
-    return 9
-
-  proc varintWrite32(z: ptr UncheckedArray[byte]; y: uint32) =
-    z[0] = uint8(y shr 24)
-    z[1] = uint8(y shr 16)
-    z[2] = uint8(y shr 8)
-    z[3] = uint8(y)
-
-  proc sqlite4PutVarint64(z: ptr UncheckedArray[byte], x: uint64): int =
-    ## Write a varint into z. The buffer z must be at least 9 characters
-    ## long to accommodate the largest possible varint. Returns the number of
-    ## bytes used.
-    if x <= 240:
-      z[0] = uint8 x
-      return 1
-    if x <= 2287:
-      y = uint32(x - 240)
-      z[0] = uint8(y shr 8 + 241)
-      z[1] = uint8(y and 255)
-      return 2
-    if x <= 67823:
-      y = uint32(x - 2288)
-      z[0] = 249
-      z[1] = uint8(y shr 8)
-      z[2] = uint8(y and 255)
-      return 3
-    let y = uint32 x
-    let w = uint32(x shr 32)
-    if w == 0:
-      if y <= 16777215:
-        z[0] = 250
-        z[1] = uint8(y shr 16)
-        z[2] = uint8(y shr 8)
-        z[3] = uint8(y)
-        return 4
-      z[0] = 251
-      varintWrite32(z+1, y)
-      return 5
-    if w <= 255:
-      z[0] = 252
-      z[1] = uint8 w
-      varintWrite32(z+2, y)
-      return 6
-    if w <= 65535:
-      z[0] = 253
-      z[1] = uint8(w shr 8)
-      z[2] = uint8 w
-      varintWrite32(z+3, y)
-      return 7
-    if w <= 16777215:
-      z[0] = 254
-      z[1] = uint8(w shr 16)
-      z[2] = uint8(w shr 8)
-      z[3] = uint8 w
-      varintWrite32(z+4, y)
-      return 8
-    z[0] = 255
-    varintWrite32(z+1, w)
-    varintWrite32(z+5, y)
-    return 9
-
-  template field(x: BiggestInt; action: SerializationAction) =
-    when action == acRead:
-      readBiggestInt(x)
-    else:
-      writeBiggestInt()
diff --git a/compiler/rodread.nim b/compiler/rodread.nim
index 4ada148c5..aa699e337 100644
--- a/compiler/rodread.nim
+++ b/compiler/rodread.nim
@@ -126,8 +126,8 @@ type
     s: cstring               # mmap'ed file contents
     options: TOptions
     reason: TReasonForRecompile
-    modDeps: seq[int32]
-    files: seq[int32]
+    modDeps: seq[FileIndex]
+    files: seq[FileIndex]
     dataIdx: int             # offset of start of data section
     convertersIdx: int       # offset of start of converters section
     initIdx, interfIdx, compilerProcsIdx, methodsIdx: int
@@ -163,11 +163,11 @@ proc decodeLineInfo(r: PRodReader, info: var TLineInfo) =
     else: info.col = int16(decodeVInt(r.s, r.pos))
     if r.s[r.pos] == ',':
       inc(r.pos)
-      if r.s[r.pos] == ',': info.line = -1'i16
-      else: info.line = int16(decodeVInt(r.s, r.pos))
+      if r.s[r.pos] == ',': info.line = 0'u16
+      else: info.line = uint16(decodeVInt(r.s, r.pos))
       if r.s[r.pos] == ',':
         inc(r.pos)
-        info = newLineInfo(r.files[decodeVInt(r.s, r.pos)], info.line, info.col)
+        info = newLineInfo(r.files[decodeVInt(r.s, r.pos)], int info.line, info.col)
 
 proc skipNode(r: PRodReader) =
   assert r.s[r.pos] == '('
@@ -861,29 +861,29 @@ proc loadMethods(r: PRodReader) =
     r.methods.add(rrGetSym(r, d, unknownLineInfo()))
     if r.s[r.pos] == ' ': inc(r.pos)
 
-proc getHash*(fileIdx: int32): SecureHash =
-  if fileIdx <% gMods.len and gMods[fileIdx].hashDone:
-    return gMods[fileIdx].hash
+proc getHash*(fileIdx: FileIndex): SecureHash =
+  if fileIdx.int32 <% gMods.len and gMods[fileIdx.int32].hashDone:
+    return gMods[fileIdx.int32].hash
 
   result = secureHashFile(fileIdx.toFullPath)
-  if fileIdx >= gMods.len: setLen(gMods, fileIdx+1)
-  gMods[fileIdx].hash = result
+  if fileIdx.int32 >= gMods.len: setLen(gMods, fileIdx.int32+1)
+  gMods[fileIdx.int32].hash = result
 
 template growCache*(cache, pos) =
   if cache.len <= pos: cache.setLen(pos+1)
 
-proc checkDep(fileIdx: int32; cache: IdentCache): TReasonForRecompile =
+proc checkDep(fileIdx: FileIndex; cache: IdentCache): TReasonForRecompile =
   assert fileIdx != InvalidFileIDX
-  growCache gMods, fileIdx
-  if gMods[fileIdx].reason != rrEmpty:
+  growCache gMods, fileIdx.int32
+  if gMods[fileIdx.int32].reason != rrEmpty:
     # reason has already been computed for this module:
-    return gMods[fileIdx].reason
+    return gMods[fileIdx.int32].reason
   let filename = fileIdx.toFilename
   var hash = getHash(fileIdx)
-  gMods[fileIdx].reason = rrNone  # we need to set it here to avoid cycles
+  gMods[fileIdx.int32].reason = rrNone  # we need to set it here to avoid cycles
   result = rrNone
   var rodfile = toGeneratedFile(filename.withPackageName, RodExt)
-  var r = newRodReader(rodfile, hash, fileIdx, cache)
+  var r = newRodReader(rodfile, hash, fileIdx.int32, cache)
   if r == nil:
     result = (if existsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)
   else:
@@ -907,19 +907,18 @@ proc checkDep(fileIdx: int32; cache: IdentCache): TReasonForRecompile =
     # recompilation is necessary:
     if r != nil: memfiles.close(r.memfile)
     r = nil
-  gMods[fileIdx].rd = r
-  gMods[fileIdx].reason = result  # now we know better
+  gMods[fileIdx.int32].rd = r
+  gMods[fileIdx.int32].reason = result  # now we know better
 
 proc handleSymbolFile*(module: PSym; cache: IdentCache): PRodReader =
-  let fileIdx = module.fileIdx
   if gSymbolFiles in {disabledSf, writeOnlySf, v2Sf}:
     module.id = getID()
     return nil
   idgen.loadMaxIds(options.gProjectPath / options.gProjectName)
-
+  let fileIdx = FileIndex module.fileIdx
   discard checkDep(fileIdx, cache)
-  if gMods[fileIdx].reason == rrEmpty: internalError("handleSymbolFile")
-  result = gMods[fileIdx].rd
+  if gMods[fileIdx.int32].reason == rrEmpty: internalError("handleSymbolFile")
+  result = gMods[fileIdx.int32].rd
   if result != nil:
     module.id = result.moduleID
     result.syms[module.id] = module
@@ -1153,7 +1152,7 @@ proc viewFile(rodfile: string) =
         if r.s[r.pos] == '\x0A':
           inc(r.pos)
           inc(r.line)
-        outf.write(w, " ", inclHash, "\n")
+        outf.write(w.int32, " ", inclHash, "\n")
       if r.s[r.pos] == ')': inc(r.pos)
       outf.write(")\n")
     of "DEPS":
@@ -1163,7 +1162,7 @@ proc viewFile(rodfile: string) =
         let v = int32(decodeVInt(r.s, r.pos))
         r.modDeps.add(r.files[v])
         if r.s[r.pos] == ' ': inc(r.pos)
-        outf.write(" ", r.files[v])
+        outf.write(" ", r.files[v].int32)
       outf.write("\n")
     of "INTERF",  "COMPILERPROCS":
       inc r.pos, 2
diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim
index 96deb1d5a..0ae687268 100644
--- a/compiler/rodwrite.nim
+++ b/compiler/rodwrite.nim
@@ -55,7 +55,7 @@ proc fileIdx(w: PRodWriter, filename: string): int =
   w.files[result] = filename
 
 template filename*(w: PRodWriter): string =
-  w.module.filename
+  toFilename(FileIndex w.module.position)
 
 proc newRodWriter(hash: SecureHash, module: PSym; cache: IdentCache): PRodWriter =
   new(result)
@@ -125,14 +125,14 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
     result.add('?')
     encodeVInt(n.info.col, result)
     result.add(',')
-    encodeVInt(n.info.line, result)
+    encodeVInt(int n.info.line, result)
     result.add(',')
     encodeVInt(fileIdx(w, toFullPath(n.info)), result)
   elif fInfo.line != n.info.line:
     result.add('?')
     encodeVInt(n.info.col, result)
     result.add(',')
-    encodeVInt(n.info.line, result)
+    encodeVInt(int n.info.line, result)
   elif fInfo.col != n.info.col:
     result.add('?')
     encodeVInt(n.info.col, result)
@@ -303,7 +303,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
   result.add('?')
   if s.info.col != -1'i16: encodeVInt(s.info.col, result)
   result.add(',')
-  if s.info.line != -1'i16: encodeVInt(s.info.line, result)
+  if s.info.line != 0'u16: encodeVInt(int s.info.line, result)
   result.add(',')
   encodeVInt(fileIdx(w, toFullPath(s.info)), result)
   if s.owner != nil:
@@ -642,7 +642,7 @@ proc process(c: PPassContext, n: PNode): PNode =
 
 proc myOpen(g: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
   if module.id < 0: internalError("rodwrite: module ID not set")
-  var w = newRodWriter(rodread.getHash module.fileIdx, module, cache)
+  var w = newRodWriter(rodread.getHash FileIndex module.position, module, cache)
   rawAddInterfaceSym(w, module)
   result = w
 
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 3996188dc..bcc1bba15 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -144,7 +144,7 @@ proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
 
 proc filename*(c: PContext): string =
   # the module's filename
-  return c.module.filename
+  return toFilename(FileIndex c.module.position)
 
 proc scopeDepth*(c: PContext): int {.inline.} =
   result = if c.currentScope != nil: c.currentScope.depthLevel
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 75d8cc2e0..8d7747fb4 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1095,12 +1095,12 @@ proc semAllTypeSections(c: PContext; n: PNode): PNode =
       for i in 0..<n.len:
         var f = checkModuleName(n.sons[i])
         if f != InvalidFileIDX:
-          if containsOrIncl(c.includedFiles, f):
+          if containsOrIncl(c.includedFiles, f.int):
             localError(n.info, errRecursiveDependencyX, f.toFilename)
           else:
             let code = gIncludeFile(c.graph, c.module, f, c.cache)
             gatherStmts c, code, result
-            excl(c.includedFiles, f)
+            excl(c.includedFiles, f.int)
     of nkStmtList:
       for i in 0 ..< n.len:
         gatherStmts(c, n.sons[i], result)
@@ -1784,11 +1784,11 @@ proc evalInclude(c: PContext, n: PNode): PNode =
   for i in countup(0, sonsLen(n) - 1):
     var f = checkModuleName(n.sons[i])
     if f != InvalidFileIDX:
-      if containsOrIncl(c.includedFiles, f):
+      if containsOrIncl(c.includedFiles, f.int):
         localError(n.info, errRecursiveDependencyX, f.toFilename)
       else:
         addSon(result, semStmt(c, gIncludeFile(c.graph, c.module, f, c.cache)))
-        excl(c.includedFiles, f)
+        excl(c.includedFiles, f.int)
 
 proc setLine(n: PNode, info: TLineInfo) =
   for i in 0 ..< safeLen(n): setLine(n.sons[i], info)
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index af31495aa..555ec9867 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -415,7 +415,7 @@ when defined(nimsuggest):
   # Since TLineInfo defined a == operator that doesn't include the column,
   # we map TLineInfo to a unique int here for this lookup table:
   proc infoToInt(info: TLineInfo): int64 =
-    info.fileIndex + info.line.int64 shl 32 + info.col.int64 shl 48
+    info.fileIndex.int64 + info.line.int64 shl 32 + info.col.int64 shl 48
 
   proc addNoDup(s: PSym; info: TLineInfo) =
     # ensure nothing gets too slow:
@@ -574,7 +574,7 @@ proc suggestEnum*(c: PContext; n: PNode; t: PType) =
   if outputs.len > 0: suggestQuit()
 
 proc suggestSentinel*(c: PContext) =
-  if gIdeCmd != ideSug or c.module.position != gTrackPos.fileIndex: return
+  if gIdeCmd != ideSug or c.module.position != gTrackPos.fileIndex.int32: return
   if c.compilesContextId > 0: return
   inc(c.compilesContextId)
   var outputs: Suggestions = @[]
diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim
index 4745b1ac7..4014d4c58 100644
--- a/compiler/syntaxes.nim
+++ b/compiler/syntaxes.nim
@@ -138,7 +138,7 @@ proc evalPipe(p: var TParsers, n: PNode, filename: string,
   else:
     result = applyFilter(p, n, filename, result)
 
-proc openParsers*(p: var TParsers, fileIdx: int32, inputstream: PLLStream;
+proc openParsers*(p: var TParsers, fileIdx: FileIndex, inputstream: PLLStream;
                   cache: IdentCache) =
   var s: PLLStream
   p.skin = skinStandard
@@ -155,7 +155,7 @@ proc openParsers*(p: var TParsers, fileIdx: int32, inputstream: PLLStream;
 proc closeParsers*(p: var TParsers) =
   parser.closeParser(p.parser)
 
-proc parseFile*(fileIdx: int32; cache: IdentCache): PNode {.procvar.} =
+proc parseFile*(fileIdx: FileIndex; cache: IdentCache): PNode {.procvar.} =
   var
     p: TParsers
     f: File
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 5b5ccdce4..70f79c433 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -1381,7 +1381,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcNGetLine:
       decodeB(rkNode)
       let n = regs[rb].node
-      regs[ra].node = newIntNode(nkIntLit, n.info.line)
+      regs[ra].node = newIntNode(nkIntLit, n.info.line.int)
       regs[ra].node.info = n.info
       regs[ra].node.typ = n.typ
     of opcNGetColumn:
@@ -1521,7 +1521,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       let x = newNodeI(TNodeKind(int(k)),
         if cc.kind != nkNilLit:
           cc.info
-        elif c.comesFromHeuristic.line > -1:
+        elif c.comesFromHeuristic.line != 0'u16:
           c.comesFromHeuristic
         elif c.callsite != nil and c.callsite.safeLen > 1:
           c.callsite[1].info
@@ -1748,7 +1748,7 @@ proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode,
 
   setupGlobalCtx(module, cache)
   var c = globalCtx
-  c.comesFromHeuristic.line = -1
+  c.comesFromHeuristic.line = 0'u16
 
   c.callsite = nOrig
   let start = genProc(c, sym)