summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/cgen.nim6
-rw-r--r--compiler/depends.nim4
-rw-r--r--compiler/docgen2.nim4
-rw-r--r--compiler/importer.nim2
-rw-r--r--compiler/jsgen.nim6
-rw-r--r--compiler/main.nim193
-rw-r--r--compiler/modules.nim308
-rw-r--r--compiler/nim.nim8
-rw-r--r--compiler/nimsuggest/nimsuggest.nim12
-rw-r--r--compiler/passaux.nim4
-rw-r--r--compiler/passes.nim35
-rw-r--r--compiler/rodwrite.nim4
-rw-r--r--compiler/scriptconfig.nim14
-rw-r--r--compiler/sem.nim10
-rw-r--r--compiler/semdata.nim9
-rw-r--r--compiler/semstmts.nim4
-rw-r--r--compiler/suggest.nim2
-rw-r--r--compiler/vm.nim4
18 files changed, 261 insertions, 368 deletions
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 86b0d60d0..6e18c8389 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -16,6 +16,8 @@ import
   condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
   lowerings, semparallel
 
+from modulegraphs import ModuleGraph
+
 import strutils except `%` # collides with ropes.`%`
 
 when options.hasTinyCBackend:
@@ -1174,7 +1176,7 @@ proc newModule(module: PSym): BModule =
     if (sfDeadCodeElim in module.flags):
       internalError("added pending module twice: " & module.filename)
 
-proc myOpen(module: PSym; cache: IdentCache): PPassContext =
+proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
   result = newModule(module)
   if optGenIndex in gGlobalOptions and generatedHeader == nil:
     let f = if headerFile.len > 0: headerFile else: gProjectFull
@@ -1209,7 +1211,7 @@ proc getCFile(m: BModule): string =
       else: ".c"
   result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), ext)
 
-proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
+proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext =
   assert optSymbolFiles in gGlobalOptions
   var m = newModule(module)
   readMergeInfo(getCFile(m), m)
diff --git a/compiler/depends.nim b/compiler/depends.nim
index f8b8a3d71..9087f89f2 100644
--- a/compiler/depends.nim
+++ b/compiler/depends.nim
@@ -12,6 +12,8 @@
 import
   os, options, ast, astalgo, msgs, ropes, idents, passes, importer
 
+from modulegraphs import ModuleGraph
+
 proc generateDot*(project: string)
 
 type
@@ -46,7 +48,7 @@ proc generateDot(project: string) =
       rope(changeFileExt(extractFilename(project), "")), gDotGraph],
             changeFileExt(project, "dot"))
 
-proc myOpen(module: PSym; cache: IdentCache): PPassContext =
+proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
   var g: PGen
   new(g)
   g.module = module
diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim
index 17b6caaba..9504ab52f 100644
--- a/compiler/docgen2.nim
+++ b/compiler/docgen2.nim
@@ -13,6 +13,8 @@
 import
   os, options, ast, astalgo, msgs, ropes, idents, passes, docgen
 
+from modulegraphs import ModuleGraph
+
 type
   TGen = object of TPassContext
     doc: PDoc
@@ -49,7 +51,7 @@ proc processNodeJson(c: PPassContext, n: PNode): PNode =
   var g = PGen(c)
   generateJson(g.doc, n)
 
-proc myOpen(module: PSym; cache: IdentCache): PPassContext =
+proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
   var g: PGen
   new(g)
   g.module = module
diff --git a/compiler/importer.nim b/compiler/importer.nim
index 771ab35d0..ce365c4dc 100644
--- a/compiler/importer.nim
+++ b/compiler/importer.nim
@@ -162,7 +162,7 @@ proc importModuleAs(n: PNode, realModule: PSym): PSym =
 proc myImportModule(c: PContext, n: PNode): PSym =
   var f = checkModuleName(n)
   if f != InvalidFileIDX:
-    result = importModuleAs(n, gImportModule(c.module, f, c.cache))
+    result = importModuleAs(n, gImportModule(c.graph, c.module, f, c.cache))
     # we cannot perform this check reliably because of
     # test: modules/import_in_config)
     if result.info.fileIndex == c.module.info.fileIndex and
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index eaa492a27..028dd00f0 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -35,6 +35,8 @@ import
   times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils,
   intsets, cgmeth, lowerings
 
+from modulegraphs import ModuleGraph
+
 type
   TTarget = enum
     targetJS, targetPHP
@@ -2272,11 +2274,11 @@ proc myClose(b: PPassContext, n: PNode): PNode =
     for obj, content in items(globals.classes):
       genClass(obj, content, ext)
 
-proc myOpenCached(s: PSym, rd: PRodReader): PPassContext =
+proc myOpenCached(graph: ModuleGraph; s: PSym, rd: PRodReader): PPassContext =
   internalError("symbol files are not possible with the JS code generator")
   result = nil
 
-proc myOpen(s: PSym; cache: IdentCache): PPassContext =
+proc myOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext =
   var r = newModule(s)
   r.target = if gCmd == cmdCompileToPHP: targetPHP else: targetJS
   result = r
diff --git a/compiler/main.nim b/compiler/main.nim
index 103eef877..2118078be 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -15,7 +15,8 @@ import
   wordrecg, sem, semdata, idents, passes, docgen, extccomp,
   cgen, jsgen, json, nversion,
   platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
-  docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists
+  docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists,
+  modulegraphs
 
 from magicsys import systemModule, resetSysTypes
 
@@ -30,80 +31,44 @@ proc semanticPasses =
   registerPass verbosePass
   registerPass semPass
 
-proc commandGenDepend(cache: IdentCache) =
+proc commandGenDepend(graph: ModuleGraph; cache: IdentCache) =
   semanticPasses()
   registerPass(gendependPass)
   registerPass(cleanupPass)
-  compileProject(cache)
+  compileProject(graph, cache)
   generateDot(gProjectFull)
   execExternalProgram("dot -Tpng -o" & changeFileExt(gProjectFull, "png") &
       ' ' & changeFileExt(gProjectFull, "dot"))
 
-proc commandCheck(cache: IdentCache) =
+proc commandCheck(graph: ModuleGraph; cache: IdentCache) =
   msgs.gErrorMax = high(int)  # do not stop after first error
   defineSymbol("nimcheck")
   semanticPasses()            # use an empty backend for semantic checking only
   rodPass()
-  compileProject(cache)
+  compileProject(graph, cache)
 
-proc commandDoc2(cache: IdentCache; json: bool) =
+proc commandDoc2(graph: ModuleGraph; cache: IdentCache; json: bool) =
   msgs.gErrorMax = high(int)  # do not stop after first error
   semanticPasses()
   if json: registerPass(docgen2JsonPass)
   else: registerPass(docgen2Pass)
   #registerPass(cleanupPass())
-  compileProject(cache)
+  compileProject(graph, cache)
   finishDoc2Pass(gProjectName)
 
-proc commandCompileToC(cache: IdentCache) =
+proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) =
   extccomp.initVars()
   semanticPasses()
   registerPass(cgenPass)
   rodPass()
   #registerPass(cleanupPass())
 
-  compileProject(cache)
+  compileProject(graph, cache)
   cgenWriteModules()
   if gCmd != cmdRun:
     extccomp.callCCompiler(changeFileExt(gProjectFull, ""))
 
-  if isServing:
-    # caas will keep track only of the compilation commands
-    lastCaasCmd = curCaasCmd
-    resetCgenModules()
-    for i in 0 .. <gMemCacheData.len:
-      gMemCacheData[i].hashStatus = hashCached
-      gMemCacheData[i].needsRecompile = Maybe
-
-      # XXX: clean these global vars
-      # ccgstmts.gBreakpoints
-      # ccgthreadvars.nimtv
-      # ccgthreadvars.nimtVDeps
-      # ccgthreadvars.nimtvDeclared
-      # cgendata
-      # cgmeth?
-      # condsyms?
-      # depends?
-      # lexer.gLinesCompiled
-      # msgs - error counts
-      # magicsys, when system.nim changes
-      # rodread.rodcompilerProcs
-      # rodread.gTypeTable
-      # rodread.gMods
-
-      # !! ropes.cache
-      # semthreads.computed?
-      #
-      # suggest.usageSym
-      #
-      # XXX: can we run out of IDs?
-      # XXX: detect config reloading (implement as error/require restart)
-      # XXX: options are appended (they will accumulate over time)
-    resetCompilationLists()
-    ccgutils.resetCaches()
-    GC_fullCollect()
-
-proc commandCompileToJS(cache: IdentCache) =
+proc commandCompileToJS(graph: ModuleGraph; cache: IdentCache) =
   #incl(gGlobalOptions, optSafeCode)
   setTarget(osJS, cpuJS)
   #initDefines()
@@ -113,9 +78,9 @@ proc commandCompileToJS(cache: IdentCache) =
   if gCmd == cmdCompileToPHP: defineSymbol("nimphp")
   semanticPasses()
   registerPass(JSgenPass)
-  compileProject(cache)
+  compileProject(graph, cache)
 
-proc interactivePasses(cache: IdentCache) =
+proc interactivePasses(graph: ModuleGraph; cache: IdentCache) =
   #incl(gGlobalOptions, optSafeCode)
   #setTarget(osNimrodVM, cpuNimrodVM)
   initDefines()
@@ -125,28 +90,28 @@ proc interactivePasses(cache: IdentCache) =
   registerPass(semPass)
   registerPass(evalPass)
 
-proc commandInteractive(cache: IdentCache) =
+proc commandInteractive(graph: ModuleGraph; cache: IdentCache) =
   msgs.gErrorMax = high(int)  # do not stop after first error
-  interactivePasses(cache)
-  compileSystemModule(cache)
+  interactivePasses(graph, cache)
+  compileSystemModule(graph, cache)
   if commandArgs.len > 0:
-    discard compileModule(fileInfoIdx(gProjectFull), cache, {})
+    discard graph.compileModule(fileInfoIdx(gProjectFull), cache, {})
   else:
-    var m = makeStdinModule()
+    var m = graph.makeStdinModule()
     incl(m.flags, sfMainModule)
-    processModule(m, llStreamOpenStdIn(), nil, cache)
+    processModule(graph, m, llStreamOpenStdIn(), nil, cache)
 
 const evalPasses = [verbosePass, semPass, evalPass]
 
-proc evalNim(nodes: PNode, module: PSym; cache: IdentCache) =
-  carryPasses(nodes, module, cache, evalPasses)
+proc evalNim(graph: ModuleGraph; nodes: PNode, module: PSym; cache: IdentCache) =
+  carryPasses(graph, nodes, module, cache, evalPasses)
 
-proc commandEval(cache: IdentCache; exp: string) =
+proc commandEval(graph: ModuleGraph; cache: IdentCache; exp: string) =
   if systemModule == nil:
-    interactivePasses(cache)
-    compileSystemModule(cache)
+    interactivePasses(graph, cache)
+    compileSystemModule(graph, cache)
   let echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
-  evalNim(echoExp.parseString(cache), makeStdinModule(), cache)
+  evalNim(graph, echoExp.parseString(cache), makeStdinModule(graph), cache)
 
 proc commandScan(cache: IdentCache) =
   var f = addFileExt(mainCommandArg(), NimExt)
@@ -165,75 +130,11 @@ proc commandScan(cache: IdentCache) =
   else:
     rawMessage(errCannotOpenFile, f)
 
-proc commandSuggest(cache: IdentCache) =
-  if isServing:
-    # XXX: hacky work-around ahead
-    # Currently, it's possible to issue a idetools command, before
-    # issuing the first compile command. This will leave the compiler
-    # cache in a state where "no recompilation is necessary", but the
-    # cgen pass was never executed at all.
-    commandCompileToC(cache)
-    let gDirtyBufferIdx = gTrackPos.fileIndex
-    discard compileModule(gDirtyBufferIdx, cache, {sfDirty})
-    resetModule(gDirtyBufferIdx)
-  else:
-    msgs.gErrorMax = high(int)  # do not stop after first error
-    semanticPasses()
-    rodPass()
-    # XXX: this handles the case when the dirty buffer is the main file,
-    # but doesn't handle the case when it's imported module
-    #var projFile = if gProjectMainIdx == gDirtyOriginalIdx: gDirtyBufferIdx
-    #               else: gProjectMainIdx
-    compileProject(cache) #(projFile)
-
-proc resetMemory =
-  resetCompilationLists()
-  ccgutils.resetCaches()
-  resetAllModules()
-  resetRopeCache()
-  resetSysTypes()
-  gOwners = @[]
-  resetIdentCache()
-
-  # XXX: clean these global vars
-  # ccgstmts.gBreakpoints
-  # ccgthreadvars.nimtv
-  # ccgthreadvars.nimtVDeps
-  # ccgthreadvars.nimtvDeclared
-  # cgendata
-  # cgmeth?
-  # condsyms?
-  # depends?
-  # lexer.gLinesCompiled
-  # msgs - error counts
-  # magicsys, when system.nim changes
-  # rodread.rodcompilerProcs
-  # rodread.gTypeTable
-  # rodread.gMods
-
-  # !! ropes.cache
-  #
-  # suggest.usageSym
-  #
-  # XXX: can we run out of IDs?
-  # XXX: detect config reloading (implement as error/require restart)
-  # XXX: options are appended (they will accumulate over time)
-  # vis = visimpl
-  when compileOption("gc", "v2"):
-    gcDebugging = true
-    echo "COLLECT 1"
-    GC_fullCollect()
-    echo "COLLECT 2"
-    GC_fullCollect()
-    echo "COLLECT 3"
-    GC_fullCollect()
-    echo GC_getStatistics()
-
 const
   SimulateCaasMemReset = false
   PrintRopeCacheStats = false
 
-proc mainCommand*(cache: IdentCache) =
+proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
   when SimulateCaasMemReset:
     gGlobalOptions.incl(optCaasEnabled)
 
@@ -249,28 +150,28 @@ proc mainCommand*(cache: IdentCache) =
   of "c", "cc", "compile", "compiletoc":
     # compile means compileToC currently
     gCmd = cmdCompileToC
-    commandCompileToC(cache)
+    commandCompileToC(graph, cache)
   of "cpp", "compiletocpp":
     gCmd = cmdCompileToCpp
     defineSymbol("cpp")
-    commandCompileToC(cache)
+    commandCompileToC(graph, cache)
   of "objc", "compiletooc":
     gCmd = cmdCompileToOC
     defineSymbol("objc")
-    commandCompileToC(cache)
+    commandCompileToC(graph, cache)
   of "run":
     gCmd = cmdRun
     when hasTinyCBackend:
       extccomp.setCC("tcc")
-      commandCompileToC(cache)
+      commandCompileToC(graph, cache)
     else:
       rawMessage(errInvalidCommandX, command)
   of "js", "compiletojs":
     gCmd = cmdCompileToJS
-    commandCompileToJS(cache)
+    commandCompileToJS(graph, cache)
   of "php":
     gCmd = cmdCompileToPHP
-    commandCompileToJS(cache)
+    commandCompileToJS(graph, cache)
   of "doc":
     wantMainModule()
     gCmd = cmdDoc
@@ -280,7 +181,7 @@ proc mainCommand*(cache: IdentCache) =
     gCmd = cmdDoc
     loadConfigs(DocConfig, cache)
     defineSymbol("nimdoc")
-    commandDoc2(cache, false)
+    commandDoc2(graph, cache, false)
   of "rst2html":
     gCmd = cmdRst2html
     loadConfigs(DocConfig, cache)
@@ -301,14 +202,14 @@ proc mainCommand*(cache: IdentCache) =
     loadConfigs(DocConfig, cache)
     wantMainModule()
     defineSymbol("nimdoc")
-    commandDoc2(cache, true)
+    commandDoc2(graph, cache, true)
   of "buildindex":
     gCmd = cmdDoc
     loadConfigs(DocConfig, cache)
     commandBuildIndex()
   of "gendepend":
     gCmd = cmdGenDepend
-    commandGenDepend(cache)
+    commandGenDepend(graph, cache)
   of "dump":
     gCmd = cmdDump
     if getConfigVar("dump.format") == "json":
@@ -337,7 +238,7 @@ proc mainCommand*(cache: IdentCache) =
       for it in iterSearchPath(searchPaths): msgWriteln(it)
   of "check":
     gCmd = cmdCheck
-    commandCheck(cache)
+    commandCheck(graph, cache)
   of "parse":
     gCmd = cmdParse
     wantMainModule()
@@ -346,26 +247,12 @@ proc mainCommand*(cache: IdentCache) =
     gCmd = cmdScan
     wantMainModule()
     commandScan(cache)
-    msgWriteln("Beware: Indentation tokens depend on the parser\'s state!")
+    msgWriteln("Beware: Indentation tokens depend on the parser's state!")
   of "secret":
     gCmd = cmdInteractive
-    commandInteractive(cache)
+    commandInteractive(graph, cache)
   of "e":
-    # XXX: temporary command for easier testing
-    commandEval(cache, mainCommandArg())
-  of "reset":
-    resetMemory()
-  of "idetools":
-    gCmd = cmdIdeTools
-    if gEvalExpr != "":
-      commandEval(cache, gEvalExpr)
-    else:
-      commandSuggest(cache)
-  of "serve":
-    isServing = true
-    gGlobalOptions.incl(optCaasEnabled)
-    msgs.gErrorMax = high(int)  # do not stop after first error
-    serve(cache, mainCommand)
+    commandEval(graph, cache, mainCommandArg())
   of "nop", "help":
     # prevent the "success" message:
     gCmd = cmdDump
@@ -393,4 +280,4 @@ proc mainCommand*(cache: IdentCache) =
 
   resetAttributes()
 
-proc mainCommand*() = mainCommand(newIdentCache())
+proc mainCommand*() = mainCommand(newModuleGraph(), newIdentCache())
diff --git a/compiler/modules.nim b/compiler/modules.nim
index be1de16d9..e901ba896 100644
--- a/compiler/modules.nim
+++ b/compiler/modules.nim
@@ -7,130 +7,118 @@
 #    distribution, for details about the copyright.
 #
 
-## implements the module handling
+## Implements the module handling, including the caching of modules.
 
 import
   ast, astalgo, magicsys, securehash, rodread, msgs, cgendata, sigmatch, options,
-  idents, os, lexer, idgen, passes, syntaxes, llstream
-
-type
-  TNeedRecompile* = enum Maybe, No, Yes, Probing, Recompiled
-  THashStatus* = enum hashNotTaken, hashCached, hashHasChanged, hashNotChanged
-
-  TModuleInMemory* = object
-    compiledAt*: float
-    hash*: SecureHash
-    deps*: seq[int32] ## XXX: slurped files are currently not tracked
-    needsRecompile*: TNeedRecompile
-    hashStatus*: THashStatus
-
-var
-  gCompiledModules: seq[PSym] = @[]
-  gMemCacheData*: seq[TModuleInMemory] = @[]
-    ## XXX: we should implement recycling of file IDs
-    ## if the user keeps renaming modules, the file IDs will keep growing
-  gFuzzyGraphChecking*: bool # nimsuggest uses this. XXX figure out why.
-  packageSyms: TStrTable
-
-initStrTable(packageSyms)
-
-proc getModule*(fileIdx: int32): PSym =
-  if fileIdx >= 0 and fileIdx < gCompiledModules.len:
-    result = gCompiledModules[fileIdx]
-
-proc hashChanged(fileIdx: int32): bool =
-  internalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len
-
-  template updateStatus =
-    gMemCacheData[fileIdx].hashStatus = if result: hashHasChanged
-                                       else: hashNotChanged
-    # echo "TESTING Hash: ", fileIdx.toFilename, " ", result
-
-  case gMemCacheData[fileIdx].hashStatus
-  of hashHasChanged:
-    result = true
-  of hashNotChanged:
-    result = false
-  of hashCached:
-    let newHash = secureHashFile(fileIdx.toFullPath)
-    result = newHash != gMemCacheData[fileIdx].hash
-    gMemCacheData[fileIdx].hash = newHash
-    updateStatus()
-  of hashNotTaken:
-    gMemCacheData[fileIdx].hash = secureHashFile(fileIdx.toFullPath)
-    result = true
-    updateStatus()
-
-proc doHash(fileIdx: int32) =
-  if gMemCacheData[fileIdx].hashStatus == hashNotTaken:
-    # echo "FIRST Hash: ", fileIdx.ToFilename
-    gMemCacheData[fileIdx].hash = secureHashFile(fileIdx.toFullPath)
-
-proc addDep(x: PSym, dep: int32) =
-  growCache gMemCacheData, dep
-  gMemCacheData[x.position].deps.safeAdd(dep)
-
-proc resetModule*(fileIdx: int32) =
-  # echo "HARD RESETTING ", fileIdx.toFilename
-  if fileIdx <% gMemCacheData.len:
-    gMemCacheData[fileIdx].needsRecompile = Yes
-  if fileIdx <% gCompiledModules.len:
-    gCompiledModules[fileIdx] = nil
-  if fileIdx <% cgendata.gModules.len:
-    cgendata.gModules[fileIdx] = nil
-
-proc resetModule*(module: PSym) =
-  let conflict = getModule(module.position.int32)
-  if conflict == nil: return
-  doAssert conflict == module
-  resetModule(module.position.int32)
-  initStrTable(module.tab)
-
-proc resetAllModules* =
-  for i in 0..gCompiledModules.high:
-    if gCompiledModules[i] != nil:
-      resetModule(i.int32)
-  resetPackageCache()
-  initStrTable(packageSyms)
-  # for m in cgenModules(): echo "CGEN MODULE FOUND"
-
-proc resetAllModulesHard* =
-  resetPackageCache()
-  gCompiledModules.setLen 0
-  gMemCacheData.setLen 0
-  magicsys.resetSysTypes()
-  initStrTable(packageSyms)
-  # XXX
-  #gOwners = @[]
-
-proc checkDepMem(fileIdx: int32): TNeedRecompile =
-  template markDirty =
-    resetModule(fileIdx)
-    return Yes
-
-  if gFuzzyGraphChecking:
-    if gMemCacheData[fileIdx].needsRecompile != Maybe:
-      return gMemCacheData[fileIdx].needsRecompile
-  else:
-    # cycle detection: We claim that a cycle does no harm.
-    if gMemCacheData[fileIdx].needsRecompile == Probing:
-      return No
+  idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs
+
+when false:
+  type
+    TNeedRecompile* = enum Maybe, No, Yes, Probing, Recompiled
+    THashStatus* = enum hashNotTaken, hashCached, hashHasChanged, hashNotChanged
+
+    TModuleInMemory* = object
+      hash*: SecureHash
+      deps*: seq[int32] ## XXX: slurped files are currently not tracked
+
+      needsRecompile*: TNeedRecompile
+      hashStatus*: THashStatus
+
+  var
+    gCompiledModules: seq[PSym] = @[]
+    gMemCacheData*: seq[TModuleInMemory] = @[]
+      ## XXX: we should implement recycling of file IDs
+      ## if the user keeps renaming modules, the file IDs will keep growing
+    gFuzzyGraphChecking*: bool # nimsuggest uses this. XXX figure out why.
+
+  proc hashChanged(fileIdx: int32): bool =
+    internalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len
+
+    template updateStatus =
+      gMemCacheData[fileIdx].hashStatus = if result: hashHasChanged
+                                         else: hashNotChanged
+      # echo "TESTING Hash: ", fileIdx.toFilename, " ", result
+
+    case gMemCacheData[fileIdx].hashStatus
+    of hashHasChanged:
+      result = true
+    of hashNotChanged:
+      result = false
+    of hashCached:
+      let newHash = secureHashFile(fileIdx.toFullPath)
+      result = newHash != gMemCacheData[fileIdx].hash
+      gMemCacheData[fileIdx].hash = newHash
+      updateStatus()
+    of hashNotTaken:
+      gMemCacheData[fileIdx].hash = secureHashFile(fileIdx.toFullPath)
+      result = true
+      updateStatus()
+
+  proc doHash(fileIdx: int32) =
+    if gMemCacheData[fileIdx].hashStatus == hashNotTaken:
+      # echo "FIRST Hash: ", fileIdx.ToFilename
+      gMemCacheData[fileIdx].hash = secureHashFile(fileIdx.toFullPath)
+
+  proc resetModule*(fileIdx: int32) =
+    # echo "HARD RESETTING ", fileIdx.toFilename
+    if fileIdx <% gMemCacheData.len:
+      gMemCacheData[fileIdx].needsRecompile = Yes
+    if fileIdx <% gCompiledModules.len:
+      gCompiledModules[fileIdx] = nil
+    if fileIdx <% cgendata.gModules.len:
+      cgendata.gModules[fileIdx] = nil
+
+  proc resetModule*(module: PSym) =
+    let conflict = getModule(module.position.int32)
+    if conflict == nil: return
+    doAssert conflict == module
+    resetModule(module.position.int32)
+    initStrTable(module.tab)
+
+  proc resetAllModules* =
+    for i in 0..gCompiledModules.high:
+      if gCompiledModules[i] != nil:
+        resetModule(i.int32)
+    resetPackageCache()
+    # for m in cgenModules(): echo "CGEN MODULE FOUND"
+
+  proc resetAllModulesHard* =
+    resetPackageCache()
+    gCompiledModules.setLen 0
+    gMemCacheData.setLen 0
+    magicsys.resetSysTypes()
+    # XXX
+    #gOwners = @[]
+
+  proc checkDepMem(fileIdx: int32): TNeedRecompile =
+    template markDirty =
+      resetModule(fileIdx)
+      return Yes
+
+    if gFuzzyGraphChecking:
+      if gMemCacheData[fileIdx].needsRecompile != Maybe:
+        return gMemCacheData[fileIdx].needsRecompile
+    else:
+      # cycle detection: We claim that a cycle does no harm.
+      if gMemCacheData[fileIdx].needsRecompile == Probing:
+        return No
 
-  if optForceFullMake in gGlobalOptions or hashChanged(fileIdx):
-    markDirty()
+    if optForceFullMake in gGlobalOptions or hashChanged(fileIdx):
+      markDirty()
 
-  if gMemCacheData[fileIdx].deps != nil:
-    gMemCacheData[fileIdx].needsRecompile = Probing
-    for dep in gMemCacheData[fileIdx].deps:
-      let d = checkDepMem(dep)
-      if d in {Yes, Recompiled}:
-        # echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
-        markDirty()
+    if gMemCacheData[fileIdx].deps != nil:
+      gMemCacheData[fileIdx].needsRecompile = Probing
+      for dep in gMemCacheData[fileIdx].deps:
+        let d = checkDepMem(dep)
+        if d in {Yes, Recompiled}:
+          # echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
+          markDirty()
 
-  gMemCacheData[fileIdx].needsRecompile = No
-  return No
+    gMemCacheData[fileIdx].needsRecompile = No
+    return No
 
-proc newModule(fileIdx: int32): PSym =
+proc newModule(graph: ModuleGraph; fileIdx: int32): 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)
@@ -143,20 +131,19 @@ proc newModule(fileIdx: int32): PSym =
 
   result.info = newLineInfo(fileIdx, 1, 1)
   let pack = getIdent(getPackageName(filename))
-  var packSym = packageSyms.strTableGet(pack)
+  var packSym = graph.packageSyms.strTableGet(pack)
   if packSym == nil:
     let pck = getPackageName(filename)
     let pck2 = if pck.len > 0: pck else: "unknown"
     packSym = newSym(skPackage, getIdent(pck2), nil, result.info)
     initStrTable(packSym.tab)
-    packageSyms.strTableAdd(packSym)
+    graph.packageSyms.strTableAdd(packSym)
 
   result.owner = packSym
   result.position = fileIdx
 
-  growCache gMemCacheData, fileIdx
-  growCache gCompiledModules, fileIdx
-  gCompiledModules[result.position] = result
+  growCache graph.modules, fileIdx
+  graph.modules[result.position] = result
 
   incl(result.flags, sfUsed)
   initStrTable(result.tab)
@@ -167,13 +154,12 @@ proc newModule(fileIdx: int32): PSym =
   # strTableIncl() for error corrections:
   discard strTableIncl(packSym.tab, result)
 
-proc compileModule*(fileIdx: int32; cache: IdentCache, flags: TSymFlags): PSym =
-  result = getModule(fileIdx)
+proc compileModule*(graph: ModuleGraph; fileIdx: int32; cache: IdentCache, flags: TSymFlags): PSym =
+  result = graph.getModule(fileIdx)
   if result == nil:
-    growCache gMemCacheData, fileIdx
-    gMemCacheData[fileIdx].needsRecompile = Probing
-    result = newModule(fileIdx)
-    #var rd = handleSymbolFile(result)
+    #growCache gMemCacheData, fileIdx
+    #gMemCacheData[fileIdx].needsRecompile = Probing
+    result = newModule(graph, fileIdx)
     var rd: PRodReader
     result.flags = result.flags + flags
     if sfMainModule in result.flags:
@@ -182,44 +168,51 @@ proc compileModule*(fileIdx: int32; cache: IdentCache, flags: TSymFlags): PSym =
     if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
       rd = handleSymbolFile(result, cache)
       if result.id < 0:
-        internalError("handleSymbolFile should have set the module\'s ID")
+        internalError("handleSymbolFile should have set the module's ID")
         return
     else:
       result.id = getID()
-    let validFile = processModule(result,
+    discard processModule(graph, result,
       if sfMainModule in flags and gProjectIsStdin: stdin.llStreamOpen else: nil,
       rd, cache)
-    if optCaasEnabled in gGlobalOptions:
-      gMemCacheData[fileIdx].compiledAt = gLastCmdTime
-      gMemCacheData[fileIdx].needsRecompile = Recompiled
-      if validFile: doHash fileIdx
-  else:
-    if checkDepMem(fileIdx) == Yes:
-      result = compileModule(fileIdx, cache, flags)
-    else:
-      result = gCompiledModules[fileIdx]
-
-proc importModule*(s: PSym, fileIdx: int32; cache: IdentCache): PSym {.procvar.} =
+    #if optCaasEnabled in gGlobalOptions:
+    #  gMemCacheData[fileIdx].needsRecompile = Recompiled
+    #  if validFile: doHash fileIdx
+  elif graph.isDirty(result):
+    result.flags.excl sfDirty
+    # reset module fields:
+    initStrTable(result.tab)
+    result.ast = nil
+    discard processModule(graph, result,
+      if sfMainModule in flags and gProjectIsStdin: stdin.llStreamOpen else: nil,
+      nil, cache)
+    graph.markClientsDirty(fileIdx)
+    when false:
+      if checkDepMem(fileIdx) == Yes:
+        result = compileModule(fileIdx, cache, flags)
+      else:
+        result = gCompiledModules[fileIdx]
+
+proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: int32;
+                   cache: IdentCache): PSym {.procvar.} =
   # this is called by the semantic checking phase
-  result = compileModule(fileIdx, cache, {})
-  if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx)
+  result = compileModule(graph, fileIdx, cache, {})
+  graph.addDep(s, fileIdx)
   #if sfSystemModule in result.flags:
   #  localError(result.info, errAttemptToRedefine, result.name.s)
   # restore the notes for outer module:
   gNotes = if s.owner.id == gMainPackageId: gMainPackageNotes
            else: ForeignPackageNotes
 
-proc includeModule*(s: PSym, fileIdx: int32; cache: IdentCache): PNode {.procvar.} =
+proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: int32;
+                    cache: IdentCache): PNode {.procvar.} =
   result = syntaxes.parseFile(fileIdx, cache)
-  if optCaasEnabled in gGlobalOptions:
-    growCache gMemCacheData, fileIdx
-    addDep(s, fileIdx)
-    doHash(fileIdx)
+  graph.addDep(s, fileIdx)
 
-proc compileSystemModule*(cache: IdentCache) =
+proc compileSystemModule*(graph: ModuleGraph; cache: IdentCache) =
   if magicsys.systemModule == nil:
     systemFileIdx = fileInfoIdx(options.libpath/"system.nim")
-    discard compileModule(systemFileIdx, cache, {sfSystemModule})
+    discard graph.compileModule(systemFileIdx, cache, {sfSystemModule})
 
 proc wantMainModule* =
   if gProjectFull.len == 0:
@@ -229,18 +222,19 @@ proc wantMainModule* =
 passes.gIncludeFile = includeModule
 passes.gImportModule = importModule
 
-proc compileProject*(cache: IdentCache; projectFileIdx = -1'i32) =
+proc compileProject*(graph: ModuleGraph; cache: IdentCache;
+                     projectFileIdx = -1'i32) =
   wantMainModule()
   let systemFileIdx = fileInfoIdx(options.libpath / "system.nim")
   let projectFile = if projectFileIdx < 0: gProjectMainIdx else: projectFileIdx
   if projectFile == systemFileIdx:
-    discard compileModule(projectFile, cache, {sfMainModule, sfSystemModule})
+    discard graph.compileModule(projectFile, cache, {sfMainModule, sfSystemModule})
   else:
-    compileSystemModule(cache)
-    discard compileModule(projectFile, cache, {sfMainModule})
+    graph.compileSystemModule(cache)
+    discard graph.compileModule(projectFile, cache, {sfMainModule})
 
-proc makeModule*(filename: string): PSym =
-  result = newModule(fileInfoIdx filename)
+proc makeModule*(graph: ModuleGraph; filename: string): PSym =
+  result = graph.newModule(fileInfoIdx filename)
   result.id = getID()
 
-proc makeStdinModule*(): PSym = makeModule"stdin"
+proc makeStdinModule*(graph: ModuleGraph): PSym = graph.makeModule"stdin"
diff --git a/compiler/nim.nim b/compiler/nim.nim
index aeab9421e..f8d6b607a 100644
--- a/compiler/nim.nim
+++ b/compiler/nim.nim
@@ -14,14 +14,14 @@ when defined(gcc) and defined(windows):
     {.link: "icons/nim_icon.o".}
 
 when defined(amd64) and defined(windows) and defined(vcc):
-  {.link: "icons/nim-amd64-windows-vcc.res" .}
+  {.link: "icons/nim-amd64-windows-vcc.res".}
 when defined(i386) and defined(windows) and defined(vcc):
-  {.link: "icons/nim-i386-windows-vcc.res" .}
+  {.link: "icons/nim-i386-windows-vcc.res".}
 
 import
   commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
   extccomp, strutils, os, osproc, platform, main, parseopt, service,
-  nodejs, scriptconfig, idents
+  nodejs, scriptconfig, idents, modulegraphs
 
 when hasTinyCBackend:
   import tccgen
@@ -73,7 +73,7 @@ proc handleCmdLine(cache: IdentCache) =
     processCmdLine(passCmd2, "")
     if options.command == "":
       rawMessage(errNoCommand, command)
-    mainCommand(cache)
+    mainCommand(newModuleGraph(), cache)
     if optHints in gOptions and hintGCStats in gNotes: echo(GC_getStatistics())
     #echo(GC_getStatistics())
     if msgs.gErrorCounter == 0:
diff --git a/compiler/nimsuggest/nimsuggest.nim b/compiler/nimsuggest/nimsuggest.nim
deleted file mode 100644
index 2be368d68..000000000
--- a/compiler/nimsuggest/nimsuggest.nim
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2015 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## Nimsuggest has been moved to https://github.com/nim-lang/nimsuggest
-
-{.error: "This project has moved to the following repo: https://github.com/nim-lang/nimsuggest".}
diff --git a/compiler/passaux.nim b/compiler/passaux.nim
index dc99ffd0c..eeaf12953 100644
--- a/compiler/passaux.nim
+++ b/compiler/passaux.nim
@@ -12,7 +12,9 @@
 import
   strutils, ast, astalgo, passes, idents, msgs, options, idgen
 
-proc verboseOpen(s: PSym; cache: IdentCache): PPassContext =
+from modulegraphs import ModuleGraph
+
+proc verboseOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext =
   #MessageOut('compiling ' + s.name.s);
   result = nil                # we don't need a context
   rawMessage(hintProcessing, s.name.s)
diff --git a/compiler/passes.nim b/compiler/passes.nim
index 9e383849a..4f1d4e3aa 100644
--- a/compiler/passes.nim
+++ b/compiler/passes.nim
@@ -13,7 +13,7 @@
 import
   strutils, lists, options, ast, astalgo, llstream, msgs, platform, os,
   condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
-  nimsets, syntaxes, times, rodread, idgen
+  nimsets, syntaxes, times, rodread, idgen, modulegraphs
 
 type
   TPassContext* = object of RootObj # the pass's context
@@ -21,9 +21,9 @@ type
 
   PPassContext* = ref TPassContext
 
-  TPassOpen* = proc (module: PSym; cache: IdentCache): PPassContext {.nimcall.}
+  TPassOpen* = proc (graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext {.nimcall.}
   TPassOpenCached* =
-    proc (module: PSym, rd: PRodReader): PPassContext {.nimcall.}
+    proc (graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext {.nimcall.}
   TPassClose* = proc (p: PPassContext, n: PNode): PNode {.nimcall.}
   TPassProcess* = proc (p: PPassContext, topLevelStmt: PNode): PNode {.nimcall.}
 
@@ -48,8 +48,8 @@ proc makePass*(open: TPassOpen = nil,
 
 # the semantic checker needs these:
 var
-  gImportModule*: proc (m: PSym, fileIdx: int32; cache: IdentCache): PSym {.nimcall.}
-  gIncludeFile*: proc (m: PSym, fileIdx: int32; cache: IdentCache): PNode {.nimcall.}
+  gImportModule*: proc (graph: ModuleGraph; m: PSym, fileIdx: int32; cache: IdentCache): PSym {.nimcall.}
+  gIncludeFile*: proc (graph: ModuleGraph; m: PSym, fileIdx: int32; cache: IdentCache): PNode {.nimcall.}
 
 # implementation
 
@@ -90,29 +90,32 @@ proc registerPass*(p: TPass) =
   gPasses[gPassesLen] = p
   inc(gPassesLen)
 
-proc carryPass*(p: TPass, module: PSym; cache: IdentCache;
+proc carryPass*(g: ModuleGraph; p: TPass, module: PSym; cache: IdentCache;
                 m: TPassData): TPassData =
-  var c = p.open(module, cache)
+  var c = p.open(g, module, cache)
   result.input = p.process(c, m.input)
   result.closeOutput = if p.close != nil: p.close(c, m.closeOutput)
                        else: m.closeOutput
 
-proc carryPasses*(nodes: PNode, module: PSym; cache: IdentCache; passes: TPasses) =
+proc carryPasses*(g: ModuleGraph; nodes: PNode, module: PSym;
+                  cache: IdentCache; passes: TPasses) =
   var passdata: TPassData
   passdata.input = nodes
   for pass in passes:
-    passdata = carryPass(pass, module, cache, passdata)
+    passdata = carryPass(g, pass, module, cache, passdata)
 
-proc openPasses(a: var TPassContextArray, module: PSym; cache: IdentCache) =
+proc openPasses(g: ModuleGraph; a: var TPassContextArray;
+                module: PSym; cache: IdentCache) =
   for i in countup(0, gPassesLen - 1):
     if not isNil(gPasses[i].open):
-      a[i] = gPasses[i].open(module, cache)
+      a[i] = gPasses[i].open(g, module, cache)
     else: a[i] = nil
 
-proc openPassesCached(a: var TPassContextArray, module: PSym, rd: PRodReader) =
+proc openPassesCached(g: ModuleGraph; a: var TPassContextArray, module: PSym,
+                      rd: PRodReader) =
   for i in countup(0, gPassesLen - 1):
     if not isNil(gPasses[i].openCached):
-      a[i] = gPasses[i].openCached(module, rd)
+      a[i] = gPasses[i].openCached(g, module, rd)
       if a[i] != nil:
         a[i].fromCache = true
     else:
@@ -155,7 +158,7 @@ proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
     importStmt.addSon str
     if not processTopLevelStmt(importStmt, a): break
 
-proc processModule*(module: PSym, stream: PLLStream,
+proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
                     rd: PRodReader; cache: IdentCache): bool {.discardable.} =
   var
     p: TParsers
@@ -163,7 +166,7 @@ proc processModule*(module: PSym, stream: PLLStream,
     s: PLLStream
     fileIdx = module.fileIdx
   if rd == nil:
-    openPasses(a, module, cache)
+    openPasses(graph, a, module, cache)
     if stream == nil:
       let filename = fileIdx.toFullPathConsiderDirty
       s = llStreamOpen(filename, fmRead)
@@ -203,7 +206,7 @@ proc processModule*(module: PSym, stream: PLLStream,
     # id synchronization point for more consistent code generation:
     idSynchronizationPoint(1000)
   else:
-    openPassesCached(a, module, rd)
+    openPassesCached(graph, a, module, rd)
     var n = loadInitSection(rd)
     for i in countup(0, sonsLen(n) - 1): processTopLevelStmtCached(n.sons[i], a)
     closePassesCached(a)
diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim
index 4e8b27733..f2422f947 100644
--- a/compiler/rodwrite.nim
+++ b/compiler/rodwrite.nim
@@ -16,6 +16,8 @@ import
   condsyms, ropes, idents, securehash, rodread, passes, importer, idgen,
   rodutils
 
+from modulegraphs import ModuleGraph
+
 type
   TRodWriter = object of TPassContext
     module: PSym
@@ -633,7 +635,7 @@ proc process(c: PPassContext, n: PNode): PNode =
   else:
     discard
 
-proc myOpen(module: PSym; cache: IdentCache): PPassContext =
+proc myOpen(g: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
   if module.id < 0: internalError("rodwrite: module ID not set")
   var w = newRodWriter(module.fileIdx.getHash, module, cache)
   rawAddInterfaceSym(w, module)
diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim
index 891ee80ad..ddd73e6f8 100644
--- a/compiler/scriptconfig.nim
+++ b/compiler/scriptconfig.nim
@@ -13,7 +13,7 @@
 import
   ast, modules, idents, passes, passaux, condsyms,
   options, nimconf, lists, sem, semdata, llstream, vm, vmdef, commands, msgs,
-  os, times, osproc, wordrecg, strtabs
+  os, times, osproc, wordrecg, strtabs, modulegraphs
 
 # we support 'cmpIgnoreStyle' natively for efficiency:
 from strutils import cmpIgnoreStyle, contains
@@ -134,9 +134,11 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string): PEvalContext
   cbconf selfExe:
     setResult(a, os.getAppFilename())
 
-proc runNimScript*(cache: IdentCache; scriptName: string; freshDefines=true) =
+proc runNimScript*(cache: IdentCache; scriptName: string;
+                   freshDefines=true) =
   passes.gIncludeFile = includeModule
   passes.gImportModule = importModule
+  let graph = newModuleGraph()
   if freshDefines: initDefines()
 
   defineSymbol("nimscript")
@@ -146,15 +148,15 @@ proc runNimScript*(cache: IdentCache; scriptName: string; freshDefines=true) =
 
   appendStr(searchPaths, options.libpath)
 
-  var m = makeModule(scriptName)
+  var m = graph.makeModule(scriptName)
   incl(m.flags, sfMainModule)
   vm.globalCtx = setupVM(m, cache, scriptName)
 
-  compileSystemModule(cache)
-  discard processModule(m, llStreamOpen(scriptName, fmRead), nil, cache)
+  graph.compileSystemModule(cache)
+  discard graph.processModule(m, llStreamOpen(scriptName, fmRead), nil, cache)
 
   # ensure we load 'system.nim' again for the real non-config stuff!
-  resetAllModulesHard()
+  #resetAllModulesHard()
   vm.globalCtx = nil
   # do not remove the defined symbols
   #initDefines()
diff --git a/compiler/sem.nim b/compiler/sem.nim
index e5ce7c6ce..02c779ef0 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -18,6 +18,8 @@ import
   evaltempl, patterns, parampatterns, sempass2, nimfix.pretty, semmacrosanity,
   semparallel, lowerings, pluginsupport, plugins.active
 
+from modulegraphs import ModuleGraph
+
 when defined(nimfix):
   import nimfix.prettybase
 
@@ -398,8 +400,8 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
         addSon(n, prc.ast)
   c.lastGenericIdx = c.generics.len
 
-proc myOpen(module: PSym; cache: IdentCache): PPassContext =
-  var c = newContext(module, cache)
+proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
+  var c = newContext(graph, module, cache)
   if c.p != nil: internalError(module.info, "sem.myOpen")
   c.semConstExpr = semConstExpr
   c.semExpr = semExpr
@@ -428,8 +430,8 @@ proc myOpen(module: PSym; cache: IdentCache): PPassContext =
     gNotes = ForeignPackageNotes
   result = c
 
-proc myOpenCached(module: PSym; rd: PRodReader): PPassContext =
-  result = myOpen(module, rd.cache)
+proc myOpenCached(graph: ModuleGraph; module: PSym; rd: PRodReader): PPassContext =
+  result = myOpen(graph, module, rd.cache)
   for m in items(rd.methods): methodDef(m, true)
 
 proc isImportSystemStmt(n: PNode): bool =
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 9a6011834..5b84b7cdf 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2012 Andreas Rumpf
+#        (c) Copyright 2016 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -13,7 +13,8 @@ import
   strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab,
   wordrecg,
   ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math,
-  magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef
+  magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef,
+  modulegraphs
 
 type
   TOptionEntry* = object of lists.TListEntry # entries to put on a
@@ -107,6 +108,7 @@ type
                             op: TTypeAttachedOp; col: int): PSym {.nimcall.}
     selfName*: PIdent
     cache*: IdentCache
+    graph*: ModuleGraph
     signatures*: TStrTable
 
 proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
@@ -151,7 +153,7 @@ proc newOptionEntry*(): POptionEntry =
   result.dynlib = nil
   result.notes = gNotes
 
-proc newContext*(module: PSym; cache: IdentCache): PContext =
+proc newContext*(graph: ModuleGraph; module: PSym; cache: IdentCache): PContext =
   new(result)
   result.ambiguousSymbols = initIntSet()
   initLinkedList(result.optionStack)
@@ -166,6 +168,7 @@ proc newContext*(module: PSym; cache: IdentCache): PContext =
   result.generics = @[]
   result.unknownIdents = initIntSet()
   result.cache = cache
+  result.graph = graph
   initStrTable(result.signatures)
 
 
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index f8ec00b23..0c6f6848e 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -820,7 +820,7 @@ proc semAllTypeSections(c: PContext; n: PNode): PNode =
           if containsOrIncl(c.includedFiles, f):
             localError(n.info, errRecursiveDependencyX, f.toFilename)
           else:
-            let code = gIncludeFile(c.module, f, c.cache)
+            let code = gIncludeFile(c.graph, c.module, f, c.cache)
             gatherStmts c, code, result
             excl(c.includedFiles, f)
     of nkStmtList:
@@ -1418,7 +1418,7 @@ proc evalInclude(c: PContext, n: PNode): PNode =
       if containsOrIncl(c.includedFiles, f):
         localError(n.info, errRecursiveDependencyX, f.toFilename)
       else:
-        addSon(result, semStmt(c, gIncludeFile(c.module, f, c.cache)))
+        addSon(result, semStmt(c, gIncludeFile(c.graph, c.module, f, c.cache)))
         excl(c.includedFiles, f)
 
 proc setLine(n: PNode, info: TLineInfo) =
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index 558581e04..39689099a 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -233,7 +233,7 @@ proc suggestFieldAccess(c: PContext, n: PNode, outputs: var int) =
         # error: no known module name:
         typ = nil
       else:
-        let m = gImportModule(c.module, fullpath.fileInfoIdx, c.cache)
+        let m = gImportModule(c.graph, c.module, fullpath.fileInfoIdx, c.cache)
         if m == nil: typ = nil
         else:
           for it in items(n.sym.tab):
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 8e1c9f661..1bb440c6c 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -24,6 +24,8 @@ import
 from semfold import leValueConv, ordinalValToString
 from evaltempl import evalTemplate
 
+from modulegraphs import ModuleGraph
+
 when hasFFI:
   import evalffi
 
@@ -1516,7 +1518,7 @@ proc setupGlobalCtx(module: PSym; cache: IdentCache) =
   else:
     refresh(globalCtx, module)
 
-proc myOpen(module: PSym; cache: IdentCache): PPassContext =
+proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
   #var c = newEvalContext(module, emRepl)
   #c.features = {allowCast, allowFFI, allowInfiniteLoops}
   #pushStackFrame(c, newStackFrame())