summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2011-12-12 01:40:47 +0100
committerAraq <rumpf_a@web.de>2011-12-12 01:40:47 +0100
commit98ed7fbf16735704b024dcac395e750d429f6e6d (patch)
tree934117703d5a9f4760bbb31a9af8946da69bca71
parent94358e03e914e171182a6773e51d9ec33a593aa5 (diff)
parentcaa4766a33050d7fb89565da128afd2da8272e1c (diff)
downloadNim-98ed7fbf16735704b024dcac395e750d429f6e6d.tar.gz
Merge branch 'master' of github.com:Araq/Nimrod
-rwxr-xr-xcompiler/c2nim/clex.nim8
-rwxr-xr-xcompiler/commands.nim10
-rwxr-xr-xcompiler/depends.nim4
-rwxr-xr-xcompiler/docgen.nim13
-rwxr-xr-xcompiler/importer.nim39
-rwxr-xr-xcompiler/lexer.nim8
-rwxr-xr-xcompiler/main.nim26
-rwxr-xr-xcompiler/msgs.nim73
-rwxr-xr-xcompiler/nimrod.cfg1
-rwxr-xr-xcompiler/nimrod.nim4
-rwxr-xr-xcompiler/options.nim29
-rwxr-xr-xcompiler/rodread.nim13
-rwxr-xr-xcompiler/rodwrite.nim17
-rwxr-xr-xcompiler/seminst.nim3
-rwxr-xr-xcompiler/semstmts.nim10
-rwxr-xr-xcompiler/semtempl.nim3
-rwxr-xr-xcompiler/semtypes.nim6
-rwxr-xr-xcompiler/sigmatch.nim2
-rwxr-xr-xconfig/nimrod.cfg2
-rwxr-xr-xlib/pure/os.nim49
-rwxr-xr-xlib/pure/times.nim2
-rw-r--r--lib/pure/unittest.nim4
-rwxr-xr-xlib/windows/winlean.nim40
-rw-r--r--tests/compile/ttypeselectors.nim3
24 files changed, 223 insertions, 146 deletions
diff --git a/compiler/c2nim/clex.nim b/compiler/c2nim/clex.nim
index 5a67f9475..53f230b7b 100755
--- a/compiler/c2nim/clex.nim
+++ b/compiler/c2nim/clex.nim
@@ -97,7 +97,7 @@ type
     next*: ref TToken         # for C we need arbitrary look-ahead :-(
   
   TLexer* = object of TBaseLexer
-    filename*: string
+    fileIdx*: int32
     inDirective: bool
   
 proc getTok*(L: var TLexer, tok: var TToken)
@@ -117,7 +117,7 @@ proc fillToken(L: var TToken) =
   
 proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) = 
   openBaseLexer(lex, inputstream)
-  lex.filename = filename
+  lex.fileIdx = filename.fileInfoIdx
 
 proc closeLexer*(lex: var TLexer) = 
   inc(gLinesCompiled, lex.LineNumber)
@@ -127,13 +127,13 @@ proc getColumn*(L: TLexer): int =
   result = getColNumber(L, L.bufPos)
 
 proc getLineInfo*(L: TLexer): TLineInfo = 
-  result = newLineInfo(L.filename, L.linenumber, getColNumber(L, L.bufpos))
+  result = newLineInfo(L.fileIdx, L.linenumber, getColNumber(L, L.bufpos))
 
 proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") = 
   msgs.GenericMessage(getLineInfo(L), msg, arg)
 
 proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") = 
-  var info = newLineInfo(L.filename, L.linenumber, pos - L.lineStart)
+  var info = newLineInfo(L.fileIdx, L.linenumber, pos - L.lineStart)
   msgs.GenericMessage(info, msg, arg)
 
 proc TokKindToStr*(k: TTokKind): string =
diff --git a/compiler/commands.nim b/compiler/commands.nim
index bce24c5da..f07361abe 100755
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -459,9 +459,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
     if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
     else: InvalidCmdLineOption(pass, switch, info)
   
-proc ProcessCommand(switch: string, pass: TCmdLinePass) = 
-  var
-    cmd, arg: string
-  var info = newLineInfo("command line", 1, 1)
-  splitSwitch(switch, cmd, arg, pass, info)
-  ProcessSwitch(cmd, arg, pass, info)
+proc ProcessCommand(switch: string, pass: TCmdLinePass) =
+  var cmd, arg: string
+  splitSwitch(switch, cmd, arg, pass, gCmdLineInfo)
+  processSwitch(cmd, arg, pass, gCmdLineInfo)
diff --git a/compiler/depends.nim b/compiler/depends.nim
index 05d176436..ac3f13a9b 100755
--- a/compiler/depends.nim
+++ b/compiler/depends.nim
@@ -33,10 +33,10 @@ proc addDotDependency(c: PPassContext, n: PNode): PNode =
   case n.kind
   of nkImportStmt: 
     for i in countup(0, sonsLen(n) - 1): 
-      var imported = splitFile(getModuleFile(n.sons[i])).name
+      var imported = getModuleName(n.sons[i])
       addDependencyAux(g.module.name.s, imported)
   of nkFromStmt: 
-    var imported = splitFile(getModuleFile(n.sons[0])).name
+    var imported = getModuleName(n.sons[0])
     addDependencyAux(g.module.name.s, imported)
   of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr: 
     for i in countup(0, sonsLen(n) - 1): discard addDotDependency(c, n.sons[i])
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 36eff2576..0f8018714 100755
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -13,7 +13,7 @@
 
 import 
   ast, astalgo, strutils, hashes, options, nversion, msgs, os, ropes, idents, 
-  wordrecg, math, syntaxes, renderer, lexer, rst, times, highlite
+  wordrecg, math, syntaxes, renderer, lexer, rst, times, highlite, importer
 
 proc CommandDoc*()
 proc CommandRst2Html*()
@@ -760,21 +760,12 @@ proc renderRstToOut(d: PDoc, n: PRstNode): PRope =
 proc checkForFalse(n: PNode): bool = 
   result = n.kind == nkIdent and IdentEq(n.ident, "false")
   
-proc getModuleFile(n: PNode): string = 
-  case n.kind
-  of nkStrLit, nkRStrLit, nkTripleStrLit: result = n.strVal
-  of nkIdent: result = n.ident.s
-  of nkSym: result = n.sym.name.s
-  else: 
-    internalError(n.info, "getModuleFile()")
-    result = ""
-  
 proc traceDeps(d: PDoc, n: PNode) = 
   const k = skModule
   if d.section[k] != nil: app(d.section[k], ", ")
   dispA(d.section[k], 
         "<a class=\"reference external\" href=\"$1.html\">$1</a>", 
-        "$1", [toRope(getModuleFile(n))])
+        "$1", [toRope(getModuleName(n))])
 
 proc generateDoc(d: PDoc, n: PNode) = 
   case n.kind
diff --git a/compiler/importer.nim b/compiler/importer.nim
index 6267cb68d..6d502f627 100755
--- a/compiler/importer.nim
+++ b/compiler/importer.nim
@@ -16,26 +16,29 @@ import
 proc evalImport*(c: PContext, n: PNode): PNode
 proc evalFrom*(c: PContext, n: PNode): PNode
 proc importAllSymbols*(c: PContext, fromMod: PSym)
-proc getModuleFile*(n: PNode): string
-# implementation
 
-proc findModule(info: TLineInfo, modulename: string): string = 
-  # returns path to module
-  result = options.FindFile(AddFileExt(modulename, nimExt))
-  if result == "": Fatal(info, errCannotOpenFile, modulename)
-  
-proc getModuleFile(n: PNode): string = 
+proc getModuleName*(n: PNode): string =
+  # This returns a short relative module name without the nim extension
+  # e.g. like "system", "importer" or "somepath/module"
+  # The proc won't perform any checks that the path is actually valid
   case n.kind
-  of nkStrLit, nkRStrLit, nkTripleStrLit: 
-    result = findModule(n.info, UnixToNativePath(n.strVal))
-  of nkIdent: 
-    result = findModule(n.info, n.ident.s)
-  of nkSym: 
-    result = findModule(n.info, n.sym.name.s)
-  else: 
-    internalError(n.info, "getModuleFile()")
+  of nkStrLit, nkRStrLit, nkTripleStrLit:
+    result = UnixToNativePath(n.strVal)
+  of nkIdent:
+    result = n.ident.s
+  of nkSym:
+    result = n.sym.name.s
+  else:
+    internalError(n.info, "getModuleName")
     result = ""
 
+proc checkModuleName*(n: PNode): string =
+  # This returns the full canonical path for a given module import
+  var modulename = n.getModuleName
+  result = findModule(modulename)
+  if result.len == 0:
+    Fatal(n.info, errCannotOpenFile, modulename)
+
 proc rawImportSymbol(c: PContext, s: PSym) = 
   # This does not handle stubs, because otherwise loading on demand would be
   # pointless in practice. So importing stubs is fine here!
@@ -103,7 +106,7 @@ proc importAllSymbols(c: PContext, fromMod: PSym) =
 proc evalImport(c: PContext, n: PNode): PNode = 
   result = n
   for i in countup(0, sonsLen(n) - 1): 
-    var f = getModuleFile(n.sons[i])
+    var f = checkModuleName(n.sons[i])
     var m = gImportModule(f)
     if sfDeprecated in m.flags: 
       Message(n.sons[i].info, warnDeprecated, m.name.s) 
@@ -114,7 +117,7 @@ proc evalImport(c: PContext, n: PNode): PNode =
 proc evalFrom(c: PContext, n: PNode): PNode = 
   result = n
   checkMinSonsLen(n, 2)
-  var f = getModuleFile(n.sons[0])
+  var f = checkModuleName(n.sons[0])
   var m = gImportModule(f)
   n.sons[0] = newSymNode(m)
   addDecl(c, m)               # add symbol to symbol table of module
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index 653644f8f..63a9bef87 100755
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -96,7 +96,7 @@ type
                               # documentation comments are here too
   
   TLexer* = object of TBaseLexer
-    filename*: string
+    fileIdx*: int32
     indentStack*: seq[int]    # the indentation stack
     dedent*: int              # counter for DED token generation
     indentAhead*: int         # if > 0 an indendation has already been read
@@ -198,7 +198,7 @@ proc fillToken(L: var TToken) =
 proc openLexer(lex: var TLexer, filename: string, inputstream: PLLStream) = 
   openBaseLexer(lex, inputstream)
   lex.indentStack = @[0]
-  lex.filename = filename
+  lex.fileIdx = filename.fileInfoIdx
   lex.indentAhead = - 1
   inc(lex.Linenumber, inputstream.lineOffset) 
 
@@ -210,13 +210,13 @@ proc getColumn(L: TLexer): int =
   result = getColNumber(L, L.bufPos)
 
 proc getLineInfo(L: TLexer): TLineInfo = 
-  result = newLineInfo(L.filename, L.linenumber, getColNumber(L, L.bufpos))
+  result = newLineInfo(L.fileIdx, L.linenumber, getColNumber(L, L.bufpos))
 
 proc lexMessage(L: TLexer, msg: TMsgKind, arg = "") = 
   msgs.Message(getLineInfo(L), msg, arg)
 
 proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") = 
-  var info = newLineInfo(L.filename, L.linenumber, pos - L.lineStart)
+  var info = newLineInfo(L.fileIdx, L.linenumber, pos - L.lineStart)
   msgs.Message(info, msg, arg)
 
 proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) = 
diff --git a/compiler/main.nim b/compiler/main.nim
index 944852bb6..0ba07900c 100755
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -15,7 +15,8 @@ import
   os, lists, condsyms, rodread, rodwrite, ropes, trees, 
   wordrecg, sem, semdata, idents, passes, docgen, extccomp,
   cgen, ecmasgen,
-  platform, nimconf, importer, passaux, depends, transf, evals, types, idgen
+  platform, nimconf, importer, passaux, depends, transf, evals, types, idgen,
+  tables
 
 const
   has_LLVM_Backend = false
@@ -27,19 +28,16 @@ proc MainCommand*()
 
 # ------------------ module handling -----------------------------------------
 
-type 
-  TFileModuleRec = tuple[filename: string, module: PSym]
-  TFileModuleMap = seq[TFileModuleRec]
+var
+  compMods = initTable[string, PSym]() # all compiled modules
 
-var compMods: TFileModuleMap = @[] # all compiled modules
+# This expects a normalized module path
+proc registerModule(filename: string, module: PSym) =
+  compMods[filename] = module
 
-proc registerModule(filename: string, module: PSym) = 
-  compMods.add((filename, module))
-
-proc getModule(filename: string): PSym = 
-  for i in countup(0, high(compMods)): 
-    if sameFile(compMods[i].filename, filename): 
-      return compMods[i].module
+# This expects a normalized module path
+proc getModule(filename: string): PSym =
+  result = compMods[filename]
 
 proc newModule(filename: string): PSym = 
   # We cannot call ``newSym`` here, because we have to circumvent the ID
@@ -71,7 +69,7 @@ proc importModule(filename: string): PSym =
 proc CompileModule(filename: string, flags: TSymFlags): PSym =
   var rd: PRodReader = nil
   var f = addFileExt(filename, nimExt)
-  result = newModule(filename)
+  result = newModule(f)
   result.flags = result.flags + flags
   if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}: 
     rd = handleSymbolFile(result, f)
@@ -178,7 +176,7 @@ proc CommandSuggest =
 
 proc wantMainModule =
   if gProjectFull.len == 0:
-    Fatal(newLineInfo("command line", 1, 1), errCommandExpectsFilename)
+    Fatal(gCmdLineInfo, errCommandExpectsFilename)
   
 proc MainCommand =
   appendStr(searchPaths, options.libpath)
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 3090198ac..ac6e6e481 100755
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -8,7 +8,7 @@
 #
 
 import
-  options, strutils, os
+  options, strutils, os, tables
 
 type 
   TMsgKind* = enum 
@@ -384,6 +384,11 @@ const
 type 
   TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
   TNoteKinds* = set[TNoteKind]
+
+  TFileInfo*{.final.} = object 
+    fullPath*: string          # This is a canonical full filesystem path
+    projPath*: string          # This is relative to the project's root
+
   TLineInfo*{.final.} = object # This is designed to be as small as possible,
                                # because it is used
                                # in syntax nodes. We safe space here by using 
@@ -395,7 +400,45 @@ type
     
   ERecoverableError* = object of EInvalidValue
 
-proc newLineInfo*(filename: string, line, col: int): TLineInfo
+var
+  filenameToIndexTbl = initTable[string, int32]()
+  fileInfos: seq[TFileInfo] = @[]
+
+proc newFileInfo(fullPath, projPath: string): TFileInfo =
+  result.fullPath = fullPath
+  result.projPath = projPath
+
+proc fileInfoIdx*(filename: string): int32 =
+  var
+    canonical: string
+    pseudoPath = false
+
+  try:
+    canonical = canonicalizePath(filename)
+  except:
+    canonical = filename
+    # The compiler uses "filenames" such as `command line` or `stdin`
+    # This flag indicates that we are working with such a path here
+    pseudoPath = true
+
+  if filenameToIndexTbl.hasKey(canonical):
+    result = filenameToIndexTbl[canonical]
+  else:
+    result = fileInfos.len.int32
+    fileInfos.add(newFileInfo(canonical, if pseudoPath: "" else: canonical.shortenDir))
+    filenameToIndexTbl[canonical] = result
+
+proc newLineInfo*(fileInfoIdx: int32, line, col: int): TLineInfo =
+  result.fileIndex = fileInfoIdx
+  result.line = int16(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)
+
 proc raiseRecoverableError*() {.noinline, noreturn.} =
   raise newException(ERecoverableError, "")
 
@@ -423,9 +466,7 @@ proc UnknownLineInfo*(): TLineInfo =
   result.fileIndex = -1
 
 var 
-  filenames: seq[tuple[filename: string, fullpath: string]] = @[]
   msgContext: seq[TLineInfo] = @[]
-  gCmdLineInfo* = newLineInfo("command line", -1, -1)
 
 proc pushInfoContext*(info: TLineInfo) = 
   msgContext.add(info)
@@ -433,31 +474,13 @@ proc pushInfoContext*(info: TLineInfo) =
 proc popInfoContext*() = 
   setlen(msgContext, len(msgContext) - 1)
 
-proc includeFilename*(f: string): int = 
-  for i in countdown(high(filenames), low(filenames)): 
-    if filenames[i].filename == f:
-      return i
-  
-  result = len(filenames)
-  
-  var fullpath: string
-  try: fullpath = expandFilename(f)
-  except: fullpath = ""
-
-  filenames.add((filename: f, fullpath: fullpath))
-
-proc newLineInfo(filename: string, line, col: int): TLineInfo = 
-  result.fileIndex = includeFilename(filename)
-  result.line = int16(line)
-  result.col = int16(col)
-
-proc ToFilename*(info: TLineInfo): string = 
+proc ToFilename*(info: TLineInfo): string =
   if info.fileIndex < 0: result = "???"
-  else: result = filenames[info.fileIndex].filename
+  else: result = fileInfos[info.fileIndex].projPath
 
 proc toFullPath*(info: TLineInfo): string =
   if info.fileIndex < 0: result = "???"
-  else: result = filenames[info.fileIndex].fullpath
+  else: result = fileInfos[info.fileIndex].fullPath
   
 proc ToLinenumber*(info: TLineInfo): int {.inline.} = 
   result = info.line
diff --git a/compiler/nimrod.cfg b/compiler/nimrod.cfg
index 5168a3bb9..7d8d4d94f 100755
--- a/compiler/nimrod.cfg
+++ b/compiler/nimrod.cfg
@@ -2,6 +2,7 @@
 
 --hint[XDeclaredButNotUsed]=off
 path="llvm"
+path="$projectPath/.."
 
 @if llvm_gcc or gcc:
   # GCC, LLVM and Visual C++ have a problem to optimize some modules.
diff --git a/compiler/nimrod.nim b/compiler/nimrod.nim
index 6a9ae690e..24dbc0617 100755
--- a/compiler/nimrod.nim
+++ b/compiler/nimrod.nim
@@ -70,14 +70,14 @@ proc HandleCmdLine() =
     ProcessCmdLine(passCmd1)
     if gProjectName != "":
       try:
-        gProjectFull = expandFilename(gProjectName)
+        gProjectFull = canonicalizePath(gProjectName)
       except EOS:
         gProjectFull = gProjectName
       var p = splitFile(gProjectFull)
       gProjectPath = p.dir
       gProjectName = p.name
     else:
-      gProjectPath = getCurrentDir()      
+      gProjectPath = getCurrentDir()
     LoadConfigs(DefaultConfig) # load all config files
     # now process command line arguments again, because some options in the
     # command line can overwite the config file's settings
diff --git a/compiler/options.nim b/compiler/options.nim
index ea36e3c6a..8aef6288c 100755
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -138,14 +138,15 @@ proc getPrefixDir*(): string =
   ## gets the application directory
   result = SplitPath(getAppDir()).head
 
+proc canonicalizePath*(path: string): string =
+  result = path.expandFilename
+  when not FileSystemCaseSensitive: result = result.toLower
+
 proc shortenDir*(dir: string): string = 
   ## returns the interesting part of a dir
   var prefix = getPrefixDir() & dirSep
   if startsWith(dir, prefix): 
     return substr(dir, len(prefix))
-  prefix = getCurrentDir() & dirSep
-  if startsWith(dir, prefix): 
-    return substr(dir, len(prefix))
   prefix = gProjectPath & dirSep
   if startsWith(dir, prefix):
     return substr(dir, len(prefix))
@@ -185,21 +186,23 @@ iterator iterSearchPath*(): string =
   var it = PStrEntry(SearchPaths.head)
   while it != nil: 
     yield it.data
-    it = PStrEntry(it.Next)  
+    it = PStrEntry(it.Next)
 
-proc rawFindFile(f: string): string = 
-  if ExistsFile(f): 
-    result = f
-  else: 
-    for it in iterSearchPath():
-      result = JoinPath(it, f)
-      if ExistsFile(result): return
-    result = ""
+proc rawFindFile(f: string): string =
+  for it in iterSearchPath():
+    result = JoinPath(it, f)
+    if ExistsFile(result):
+      return result.canonicalizePath
+  result = ""
 
 proc FindFile*(f: string): string = 
   result = rawFindFile(f)
   if len(result) == 0: result = rawFindFile(toLower(f))
-  
+
+proc findModule*(modulename: string): string {.inline.} =
+  # returns path to module
+  result = FindFile(AddFileExt(modulename, nimExt))
+
 proc binaryStrSearch*(x: openarray[string], y: string): int = 
   var a = 0
   var b = len(x) - 1
diff --git a/compiler/rodread.nim b/compiler/rodread.nim
index 2ab019c82..a73f5414f 100755
--- a/compiler/rodread.nim
+++ b/compiler/rodread.nim
@@ -576,7 +576,9 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
       L = 0
       while r.s[r.pos] > '\x0A' and r.s[r.pos] != ')': 
         setlen(r.files, L + 1)
-        r.files[L] = decodeStr(r.s, r.pos)
+        var relativePath = decodeStr(r.s, r.pos)
+        var resolvedPath = relativePath.findModule
+        r.files[L] = if resolvedPath.len > 0: resolvedPath else: relativePath
         inc(r.pos)            # skip #10
         inc(r.line)
         inc(L)
@@ -628,7 +630,8 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
       r.initIdx = r.pos + 2   # "(\10"
       skipSection(r)
     else: 
-      MsgWriteln("skipping section: " & $r.pos)
+      MsgWriteln("skipping section: " & section &
+                 " at " & $r.pos & " in " & r.filename)
       skipSection(r)
     if r.s[r.pos] == '\x0A': 
       inc(r.pos)
@@ -788,11 +791,11 @@ proc loadMethods(r: PRodReader) =
   
 proc getModuleIdx(filename: string): int = 
   for i in countup(0, high(gMods)): 
-    if sameFile(gMods[i].filename, filename): return i
+    if gMods[i].filename == filename: return i
   result = len(gMods)
   setlen(gMods, result + 1)
 
-proc checkDep(filename: string): TReasonForRecompile = 
+proc checkDep(filename: string): TReasonForRecompile =
   assert(not isNil(filename)) 
   var idx = getModuleIdx(filename)
   if gMods[idx].reason != rrEmpty: 
@@ -853,7 +856,7 @@ proc handleSymbolFile(module: PSym, filename: string): PRodReader =
   
 proc GetCRC*(filename: string): TCrc32 = 
   for i in countup(0, high(gMods)): 
-    if sameFile(gMods[i].filename, filename): return gMods[i].crc
+    if gMods[i].filename == filename: return gMods[i].crc
   
   result = crcFromFile(filename)
   #var idx = getModuleIdx(filename)
diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim
index 154dc13d4..873f97764 100755
--- a/compiler/rodwrite.nim
+++ b/compiler/rodwrite.nim
@@ -87,17 +87,18 @@ proc newRodWriter(modfilename: string, crc: TCrc32, module: PSym): PRodWriter =
   result.init = ""
   result.data = newStringOfCap(12_000)
   
-proc addModDep(w: PRodWriter, dep: string) = 
+proc addModDep(w: PRodWriter, dep: string) =
   if w.modDeps.len != 0: add(w.modDeps, ' ')
   encodeVInt(fileIdx(w, dep), w.modDeps)
 
 const 
   rodNL = "\x0A"
 
-proc addInclDep(w: PRodWriter, dep: string) = 
+proc addInclDep(w: PRodWriter, dep: string) =
+  var resolved = dep.findModule
   encodeVInt(fileIdx(w, dep), w.inclDeps)
   add(w.inclDeps, " ")
-  encodeVInt(crcFromFile(dep), w.inclDeps)
+  encodeVInt(crcFromFile(resolved), w.inclDeps)
   add(w.inclDeps, rodNL)
 
 proc pushType(w: PRodWriter, t: PType) =
@@ -555,21 +556,21 @@ proc process(c: PPassContext, n: PNode): PNode =
       #            addInterfaceSym(w, a.sons[j].sym);        
       #        end 
   of nkImportStmt: 
-    for i in countup(0, sonsLen(n) - 1): addModDep(w, getModuleFile(n.sons[i]))
+    for i in countup(0, sonsLen(n) - 1): addModDep(w, getModuleName(n.sons[i]))
     addStmt(w, n)
   of nkFromStmt: 
-    addModDep(w, getModuleFile(n.sons[0]))
+    addModDep(w, getModuleName(n.sons[0]))
     addStmt(w, n)
   of nkIncludeStmt: 
-    for i in countup(0, sonsLen(n) - 1): addInclDep(w, getModuleFile(n.sons[i]))
+    for i in countup(0, sonsLen(n) - 1): addInclDep(w, getModuleName(n.sons[i]))
   of nkPragma: 
     addStmt(w, n)
   else: 
     nil
 
-proc myOpen(module: PSym, filename: string): PPassContext = 
+proc myOpen(module: PSym, filename: string): PPassContext =
   if module.id < 0: InternalError("rodwrite: module ID not set")
-  var w = newRodWriter(filename, rodread.GetCRC(filename), module)
+  var w = newRodWriter(filename, rodread.GetCRC(module.info.toFullPath), module)
   rawAddInterfaceSym(w, module)
   result = w
 
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index d7dbe623b..641cf9a89 100755
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -135,7 +135,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   if n.sons[paramsPos].kind != nkEmpty: 
     removeDefaultParamValues(n.sons[ParamsPos])
     semParamList(c, n.sons[ParamsPos], nil, result)
-    addParams(c, result.typ.n)
+    # XXX: obsoleted - happens in semParamList # 
+    # addParams(c, result.typ.n)
   else: 
     result.typ = newTypeS(tyProc, c)
     addSon(result.typ, nil)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 2dbfa9497..29bf48c19 100755
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -616,7 +616,8 @@ proc semLambda(c: PContext, n: PNode): PNode =
     illFormedAst(n)           # process parameters:
   if n.sons[paramsPos].kind != nkEmpty: 
     semParamList(c, n.sons[ParamsPos], nil, s)
-    addParams(c, s.typ.n)
+    # XXX: obsoleted - happens in semParamList
+    # addParams(c, s.typ.n)
     ParamsTypeCheck(c, s.typ)
   else:
     s.typ = newTypeS(tyProc, c)
@@ -665,7 +666,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
         n.sons[genericParamsPos] = gp
         # check for semantics again:
         semParamList(c, n.sons[ParamsPos], nil, s)
-    addParams(c, s.typ.n)
+    # XXX: obsoleted - happens in semParamList
+    # addParams(c, s.typ.n)
   else: 
     s.typ = newTypeS(tyProc, c)
     addSon(s.typ, nil)
@@ -795,8 +797,8 @@ proc evalInclude(c: PContext, n: PNode): PNode =
   result = newNodeI(nkStmtList, n.info)
   addSon(result, n)
   for i in countup(0, sonsLen(n) - 1): 
-    var f = getModuleFile(n.sons[i])
-    var fileIndex = includeFilename(f)
+    var f = checkModuleName(n.sons[i])
+    var fileIndex = f.fileInfoIdx
     if ContainsOrIncl(c.includedFiles, fileIndex): 
       GlobalError(n.info, errRecursiveDependencyX, f)
     addSon(result, semStmt(c, gIncludeFile(f)))
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index ee540c5d2..26216ab4c 100755
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -185,7 +185,8 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
       # use ``stmt`` as implicit result type
       s.typ.sons[0] = newTypeS(tyStmt, c)
       s.typ.n.sons[0] = newNodeIT(nkType, n.info, s.typ.sons[0])
-  addParams(c, s.typ.n)       # resolve parameters:
+  # XXX: obsoleted - happens in semParamList # 
+  # addParams(c, s.typ.n)       # resolve parameters:
   var toBind = initIntSet()
   n.sons[bodyPos] = resolveTemplateParams(c, n.sons[bodyPos], false, toBind)
   if s.typ.sons[0].kind notin {tyStmt, tyTypeDesc}:
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 9e78f98e3..78a95c56b 100755
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -569,6 +569,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
         LocalError(a.sons[j].info, errAttemptToRedefine, arg.name.s)
       addSon(result.n, newSymNode(arg))
       addSon(result, typ)
+      addDecl(c, arg)
+
   if n.sons[0].kind != nkEmpty: 
     var r = paramType(c, n.sons[0], genericParams, cl)
     # turn explicit 'void' return type into 'nil' because the rest of the 
@@ -711,11 +713,13 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   of nkDistinctTy: result = semDistinct(c, n, prev)
   of nkProcTy: 
     checkSonsLen(n, 2)
-    result = semProcTypeNode(c, n.sons[0], nil, prev) 
+    openScope(c.tab)
+    result = semProcTypeNode(c, n.sons[0], nil, prev)
     # dummy symbol for `pragma`:
     var s = newSymS(skProc, newIdentNode(getIdent("dummy"), n.info), c)
     s.typ = result
     pragma(c, s, n.sons[1], procTypePragmas)
+    closeScope(c.tab)    
   of nkEnumTy: result = semEnum(c, n, prev)
   of nkType: result = n.typ
   of nkStmtListType: result = semStmtListType(c, n, prev)
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index cd6cbe859..a6bde6e40 100755
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -713,7 +713,7 @@ proc matches*(c: PContext, n: PNode, m: var TCandidate) =
 
   when false:
     if sfSystemModule notin c.module.flags:
-      if includeFilename("temp.nim") == c.module.info.fileIndex:
+      if fileInfoIdx("temp.nim") == c.module.info.fileIndex:
         echo "########################"
         echo m.call.renderTree
         for i in 1..m.call.len-1:
diff --git a/config/nimrod.cfg b/config/nimrod.cfg
index 24732cc82..b8bb77a03 100755
--- a/config/nimrod.cfg
+++ b/config/nimrod.cfg
@@ -107,7 +107,7 @@ clang.options.size = "-Os"
 
 # Configuration for the Visual C/C++ compiler:
 vcc.options.linker = "/DEBUG /Zi /Fd\"$projectName.pdb\" /F33554432" # set the stack size to 8 MB
-vcc.options.debug = "/RTC1 /Zi /Fd\"$projectName.pdb\""
+vcc.options.debug = "/Zi /Fd\"$projectName.pdb\""
 vcc.options.always = "/nologo"
 vcc.options.speed = "/Ox /arch:SSE2"
 vcc.options.size = "/O1"
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index a8fafd5de..f22a53dd8 100755
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -567,26 +567,45 @@ proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1".} =
     result = path[0] == '/'
 
 proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1".} =
-  ## Returns True if both pathname arguments refer to the same file or
-  ## directory (as indicated by device number and i-node number).
-  ## Raises an exception if an stat() call on either pathname fails.
+  ## Returns True if both pathname arguments refer to the same physical 
+  ## file or directory. Raises an exception if any of the files does not
+  ## exist or information about it can not be obtained.
+  ## 
+  ## This proc will return true if given two alternative hard-linked or
+  ## sym-linked paths to the same file or directory.
   when defined(Windows):
-    var
-      a, b: TWin32FindData
-    var resA = findfirstFileA(path1, a)
-    var resB = findfirstFileA(path2, b)
-    if resA != -1 and resB != -1:
-      result = $a.cFileName == $b.cFileName
-    else:
-      # work around some ``findfirstFileA`` bugs
-      result = cmpPaths(path1, path2) == 0
-    if resA != -1: findclose(resA)
-    if resB != -1: findclose(resB)
+    var success = true
+    
+    template OpenHandle(path: expr): expr =
+      CreateFileA(path, 0'i32, FILE_SHARE_DELETE or FILE_SHARE_READ or
+        FILE_SHARE_WRITE, nil, OPEN_EXISTING,
+        FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL, 0)
+
+    var f1 = OpenHandle(path1)
+    var f2 = OpenHandle(path2)
+
+    if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE:
+      var fi1, fi2: TBY_HANDLE_FILE_INFORMATION
+
+      if GetFileInformationByHandle(f1, addr(fi1)) != 0 and
+         GetFileInformationByHandle(f2, addr(fi2)) != 0:
+        result = fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber and
+                 fi1.nFileIndexHigh == fi2.nFileIndexHigh and
+                 fi1.nFileIndexLow == fi2.nFileIndexLow
+      else: success = false
+    else: success = false
+
+    discard CloseHandle(f1)
+    discard CloseHandle(f2)
+
+    if not success:
+      OSError()
+
   else:
     var
       a, b: TStat
     if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32:
-      result = cmpPaths(path1, path2) == 0 # be consistent with Windows
+      OSError()
     else:
       result = a.st_dev == b.st_dev and a.st_ino == b.st_ino
 
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index a4ac59673..f73a48bea 100755
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -302,7 +302,7 @@ when not defined(ECMAScript):
         posix_gettimeofday(a)
         result = toFloat(a.tv_sec) + toFloat(a.tv_usec)*0.00_0001
       elif defined(windows):
-        var f: winlean.Filetime
+        var f: winlean.TFiletime
         GetSystemTimeAsFileTime(f)
         var i64 = rdFileTime(f) - epochDiff
         var secs = i64 div rateDiff
diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim
index e2906dd1a..f9981195c 100644
--- a/lib/pure/unittest.nim
+++ b/lib/pure/unittest.nim
@@ -70,6 +70,10 @@ template test*(name: expr, body: stmt): stmt =
       TestSetupIMPL()

       body

 

+    except:

+      checkpoint("Unhandled exception: " & getCurrentExceptionMsg())

+      fail()

+

     finally:

       TestTeardownIMPL()

       testDone name, TestStatusIMPL

diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index 18e287bfa..acc28e58b 100755
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -47,6 +47,22 @@ type
     dwProcessId*: int32
     dwThreadId*: int32
 
+  TFILETIME* {.final, pure.} = object ## CANNOT BE int64 BECAUSE OF ALIGNMENT
+    dwLowDateTime*: DWORD
+    dwHighDateTime*: DWORD
+  
+  TBY_HANDLE_FILE_INFORMATION* {.final, pure.} = object
+    dwFileAttributes*: DWORD
+    ftCreationTime*: TFILETIME
+    ftLastAccessTime*: TFILETIME
+    ftLastWriteTime*: TFILETIME
+    dwVolumeSerialNumber*: DWORD
+    nFileSizeHigh*: DWORD
+    nFileSizeLow*: DWORD
+    nNumberOfLinks*: DWORD
+    nFileIndexHigh*: DWORD
+    nFileIndexLow*: DWORD
+
 const
   STARTF_USESHOWWINDOW* = 1'i32
   STARTF_USESTDHANDLES* = 256'i32
@@ -149,14 +165,11 @@ const
 
   MAX_PATH* = 260
 type
-  FILETIME* {.final, pure.} = object ## CANNOT BE int64 BECAUSE OF ALIGNMENT
-    dwLowDateTime*: int32
-    dwHighDateTime*: int32
   TWIN32_FIND_DATA* {.pure.} = object
     dwFileAttributes*: int32
-    ftCreationTime*: FILETIME
-    ftLastAccessTime*: FILETIME
-    ftLastWriteTime*: FILETIME
+    ftCreationTime*: TFILETIME
+    ftLastAccessTime*: TFILETIME
+    ftLastWriteTime*: TFILETIME
     nFileSizeHigh*: int32
     nFileSizeLow*: int32
     dwReserved0: int32
@@ -192,13 +205,13 @@ proc FreeEnvironmentStringsA*(para1: cstring): int32 {.
 
 proc GetCommandLineA*(): CString {.importc, stdcall, dynlib: "kernel32".}
 
-proc rdFileTime*(f: FILETIME): int64 = 
+proc rdFileTime*(f: TFILETIME): int64 = 
   result = ze64(f.dwLowDateTime) or (ze64(f.dwHighDateTime) shl 32)
 
 proc rdFileSize*(f: TWin32FindData): int64 = 
   result = ze64(f.nFileSizeLow) or (ze64(f.nFileSizeHigh) shl 32)
 
-proc GetSystemTimeAsFileTime*(lpSystemTimeAsFileTime: var FileTime) {.
+proc GetSystemTimeAsFileTime*(lpSystemTimeAsFileTime: var TFILETIME) {.
   importc: "GetSystemTimeAsFileTime", dynlib: "kernel32", stdcall.}
 
 proc Sleep*(dwMilliseconds: int32){.stdcall, dynlib: "kernel32",
@@ -209,12 +222,16 @@ proc ShellExecute*(HWND: THandle, lpOperation, lpFile,
                    nShowCmd: int32): THandle{.
     stdcall, dynlib: "shell32.dll", importc: "ShellExecuteA".}
 
+proc GetFileInformationByHandle*(hFile: THandle,
+  lpFileInformation: ptr TBY_HANDLE_FILE_INFORMATION): WINBOOL{.
+    stdcall, dynlib: "kernel32", importc: "GetFileInformationByHandle".}
+
 const
   WSADESCRIPTION_LEN* = 256
   WSASYS_STATUS_LEN* = 128
   FD_SETSIZE* = 64
   MSG_PEEK* = 2
-  
+ 
   INADDR_ANY* = 0
   INADDR_LOOPBACK* = 0x7F000001
   INADDR_BROADCAST* = -1
@@ -410,6 +427,9 @@ const
   GENERIC_READ* = 0x80000000'i32
   GENERIC_ALL* = 0x10000000'i32
   FILE_SHARE_READ* = 1'i32
+  FILE_SHARE_DELETE* = 4'i32
+  FILE_SHARE_WRITE* = 2'i32
+ 
   CREATE_ALWAYS* = 2'i32
   OPEN_EXISTING* = 3'i32
   FILE_BEGIN* = 0'i32
@@ -421,6 +441,8 @@ const
   FILE_MAP_WRITE* = 2'i32
   INVALID_FILE_SIZE* = -1'i32
 
+  FILE_FLAG_BACKUP_SEMANTICS* = 33554432'i32
+
 proc CreateFileA*(lpFileName: cstring, dwDesiredAccess, dwShareMode: DWORD,
                   lpSecurityAttributes: pointer,
                   dwCreationDisposition, dwFlagsAndAttributes: DWORD,
diff --git a/tests/compile/ttypeselectors.nim b/tests/compile/ttypeselectors.nim
index 7d76cafef..9ed7e2008 100644
--- a/tests/compile/ttypeselectors.nim
+++ b/tests/compile/ttypeselectors.nim
@@ -35,3 +35,6 @@ var y*: type(t2(100)) = "test"
 proc t6*(x: type(t3(0))): type(t1(0)) =
   result = $x
 
+proc t7*(x: int): type($x) =
+  result = "test"
+