summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/ast.nim17
-rwxr-xr-xcompiler/c2nim/c2nim.nim3
-rwxr-xr-xcompiler/c2nim/cparse.nim8
-rwxr-xr-xcompiler/c2nim/tests/systest.c2
-rw-r--r--compiler/ccgcalls.nim6
-rwxr-xr-xcompiler/cgen.nim58
-rw-r--r--compiler/cgendata.nim2
-rwxr-xr-xcompiler/commands.nim2
-rwxr-xr-xcompiler/extccomp.nim35
-rwxr-xr-xcompiler/lookups.nim7
-rwxr-xr-xcompiler/msgs.nim6
-rwxr-xr-xcompiler/nimrod.nim12
-rwxr-xr-xcompiler/parser.nim24
-rwxr-xr-xcompiler/pragmas.nim3
-rwxr-xr-xcompiler/semgnrc.nim20
-rwxr-xr-xcompiler/semstmts.nim8
-rwxr-xr-xcompiler/semtypes.nim6
-rwxr-xr-xcompiler/sigmatch.nim3
-rwxr-xr-xcompiler/suggest.nim27
-rwxr-xr-xcompiler/types.nim2
20 files changed, 153 insertions, 98 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 419d57562..aafd52098 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -273,6 +273,7 @@ type
 
 const
   tyPureObject* = tyTuple
+  GcTypeKinds* = {tyRef, tySequence, tyString}
 
 type
   TTypeKinds* = set[TTypeKind]
@@ -771,6 +772,14 @@ proc NewType(kind: TTypeKind, owner: PSym): PType =
   #if result.id < 2000 then
   #  MessageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
   
+proc mergeLoc(a: var TLoc, b: TLoc) =
+  if a.k == low(a.k): a.k = b.k
+  if a.s == low(a.s): a.s = b.s
+  a.flags = a.flags + b.flags
+  if a.t == nil: a.t = b.t
+  if a.r == nil: a.r = b.r
+  if a.a == 0: a.a = b.a
+  
 proc assignType(dest, src: PType) = 
   dest.kind = src.kind
   dest.flags = src.flags
@@ -779,6 +788,14 @@ proc assignType(dest, src: PType) =
   dest.size = src.size
   dest.align = src.align
   dest.containerID = src.containerID
+  # this fixes 'type TLock = TSysLock':
+  if src.sym != nil:
+    if dest.sym != nil:
+      dest.sym.flags = dest.sym.flags + src.sym.flags
+      if dest.sym.annex == nil: dest.sym.annex = src.sym.annex
+      mergeLoc(dest.sym.loc, src.sym.loc)
+    else:
+      dest.sym = src.sym
   newSons(dest, sonsLen(src))
   for i in countup(0, sonsLen(src) - 1): dest.sons[i] = src.sons[i]
   
diff --git a/compiler/c2nim/c2nim.nim b/compiler/c2nim/c2nim.nim
index 6d7a0d6c1..e408467ef 100755
--- a/compiler/c2nim/c2nim.nim
+++ b/compiler/c2nim/c2nim.nim
@@ -44,7 +44,8 @@ proc main(infile, outfile: string, options: PParserOptions) =
   var module = parseUnit(p)
   closeParser(p)
   renderModule(module, outfile)
-  rawMessage(hintSuccessX, [$gLinesCompiled, $(getTime() - start)])
+  rawMessage(hintSuccessX, [$gLinesCompiled, $(getTime() - start), 
+                            formatSize(getTotalMem())])
 
 var
   infile = ""
diff --git a/compiler/c2nim/cparse.nim b/compiler/c2nim/cparse.nim
index f8f58347d..ad583b92b 100755
--- a/compiler/c2nim/cparse.nim
+++ b/compiler/c2nim/cparse.nim
@@ -94,7 +94,7 @@ proc OpenParser(p: var TParser, filename: string,
   new(p.tok)
 
 proc parMessage(p: TParser, msg: TMsgKind, arg = "") = 
-  #assert false
+  assert false
   lexMessage(p.lex, msg, arg)
 
 proc CloseParser(p: var TParser) = CloseLexer(p.lex)
@@ -930,10 +930,8 @@ proc declaration(p: var TParser): PNode =
       parMessage(p, errTokenExpected, ";")
     if sonsLen(result.sons[pragmasPos]) == 0: 
       result.sons[pragmasPos] = ast.emptyNode
-  of pxAsgn, pxSemicolon, pxComma:
-    result = parseVarDecl(p, baseTyp, rettyp, origName)
   else:
-    parMessage(p, errTokenExpected, ";")
+    result = parseVarDecl(p, baseTyp, rettyp, origName)
   assert result != nil
 
 proc createConst(name, typ, val: PNode, p: TParser): PNode =
@@ -1594,7 +1592,7 @@ proc parseSwitch(p: var TParser): PNode =
   eat(p, pxCurlyRi)
 
 proc addStmt(sl, a: PNode) = 
-  # merge type sections is possible:
+  # merge type sections if possible:
   if a.kind != nkTypeSection or sonsLen(sl) == 0 or
       lastSon(sl).kind != nkTypeSection:
     addSon(sl, a)
diff --git a/compiler/c2nim/tests/systest.c b/compiler/c2nim/tests/systest.c
index d1fbb6784..389fdfdc2 100755
--- a/compiler/c2nim/tests/systest.c
+++ b/compiler/c2nim/tests/systest.c
@@ -351,7 +351,7 @@ HWBType;
 static HWBType *
 RGB_to_HWB (RGBType RGB, HWBType * HWB)
 {
-
+  HWBType* myArray[20];
   /*
    * RGB are each on [0, 1]. W and B are returned on [0, 1] and H is  
    * returned on [0, 6]. Exception: H is returned UNDEFINED if W == 1 - B.  
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index b28765f8f..3ea539389 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -252,7 +252,8 @@ proc genCall(p: BProc, e: PNode, d: var TLoc) =
     genNamedParamCall(p, e, d)
   else:
     genPrefixCall(p, nil, e, d)
-  if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)
+  when false:
+    if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)
 
 proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
   if ri.sons[0].kind == nkSym and sfInfixCall in ri.sons[0].sym.flags and
@@ -262,5 +263,6 @@ proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
     genNamedParamCall(p, ri, d)
   else:
     genPrefixCall(p, le, ri, d)
-  if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)
+  when false:
+    if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)
 
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 16210c026..7dfc259ef 100755
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -297,23 +297,36 @@ proc getTemp(p: BProc, t: PType, result: var TLoc) =
   initTemp(p, result)
 
 proc keepAlive(p: BProc, toKeepAlive: TLoc) =
-  if optRefcGC notin gGlobalOptions: return
-  var result: TLoc
-  inc(p.labels)
-  result.r = con("LOC", toRope(p.labels))
-  appf(p.s[cpsLocals], "volatile $1 $2;$n",
-      [getTypeDesc(p.module, toKeepAlive.t), result.r])
-  result.k = locTemp
-  result.a = -1
-  result.t = toKeepAlive.t
-  result.s = OnStack
-  result.flags = {}
-  if skipTypes(toKeepAlive.t, abstractVarRange).Kind notin complexValueType:
-    appf(p.s[cpsStmts], "$1 = $2;$n", [rdLoc(result), rdLoc(toKeepAlive)])
-  else:
-    appcg(p, cpsStmts,
-         "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
-         [addrLoc(result), addrLoc(toKeepAlive), rdLoc(result)])
+  when false:
+    # deactivated because of the huge slowdown this causes; GC will take care
+    # of interior pointers instead
+    if optRefcGC notin gGlobalOptions: return
+    var result: TLoc
+    var fid = toRope(p.gcFrameId)
+    result.r = con("GCFRAME.F", fid)
+    appf(p.gcFrameType, "  $1 F$2;$n",
+        [getTypeDesc(p.module, toKeepAlive.t), fid])
+    inc(p.gcFrameId)
+    result.k = locTemp
+    result.a = -1
+    result.t = toKeepAlive.t
+    result.s = OnStack
+    result.flags = {}
+
+    if skipTypes(toKeepAlive.t, abstractVarRange).Kind notin complexValueType:
+      appf(p.s[cpsStmts], "$1 = $2;$n", [rdLoc(result), rdLoc(toKeepAlive)])
+    else:
+      appcg(p, cpsStmts,
+           "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
+           [addrLoc(result), addrLoc(toKeepAlive), rdLoc(result)])
+
+proc initGCFrame(p: BProc): PRope =
+  if p.gcFrameId > 0: result = ropef("struct {$1} GCFRAME;$n", p.gcFrameType)
+
+proc deinitGCFrame(p: BProc): PRope =
+  if p.gcFrameId > 0:
+    result = ropecg(p.module,
+                    "if (((NU)&GCFRAME) < 4096) #nimGCFrame(&GCFRAME);$n")
 
 proc cstringLit(p: BProc, r: var PRope, s: string): PRope = 
   if gCmd == cmdCompileToLLVM: 
@@ -370,6 +383,8 @@ proc assignLocalVar(p: BProc, s: PSym) =
     if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
   app(p.s[cpsLocals], getTypeDesc(p.module, s.loc.t))
   if sfRegister in s.flags: app(p.s[cpsLocals], " register")
+  elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
+    app(p.s[cpsLocals], " GC_GUARD")
   if (sfVolatile in s.flags) or (p.nestedTryStmts.len > 0): 
     app(p.s[cpsLocals], " volatile")
   appf(p.s[cpsLocals], " $1;$n", [s.loc.r])
@@ -428,7 +443,7 @@ include "ccgexprs.nim", "ccgstmts.nim"
 proc libCandidates(s: string, dest: var TStringSeq) = 
   var le = strutils.find(s, '(')
   var ri = strutils.find(s, ')', le+1)
-  if le >= 0 and ri > le: 
+  if le >= 0 and ri > le:
     var prefix = substr(s, 0, le - 1)
     var suffix = substr(s, ri + 1)
     for middle in split(substr(s, le + 1, ri - 1), '|'):
@@ -583,8 +598,9 @@ proc genProcAux(m: BModule, prc: PSym) =
   if sfPure in prc.flags: 
     generatedProc = ropeff("$1 {$n$2$3$4}$n", "define $1 {$n$2$3$4}$n",
         [header, p.s[cpsLocals], p.s[cpsInit], p.s[cpsStmts]])
-  else: 
+  else:
     generatedProc = ropeff("$1 {$n", "define $1 {$n", [header])
+    app(generatedProc, initGCFrame(p))
     if optStackTrace in prc.options: 
       getFrameDecl(p)
       app(generatedProc, p.s[cpsLocals])
@@ -608,6 +624,7 @@ proc genProcAux(m: BModule, prc: PSym) =
     app(generatedProc, p.s[cpsInit])
     app(generatedProc, p.s[cpsStmts])
     if p.beforeRetNeeded: appf(generatedProc, "BeforeRet: $n;")
+    app(generatedProc, deinitGCFrame(p))
     if optStackTrace in prc.options: app(generatedProc, deinitFrame(p))
     if (optProfiler in prc.options) and (gCmd != cmdCompileToLLVM): 
       appf(generatedProc, 
@@ -816,6 +833,8 @@ proc genInitCode(m: BModule) =
     m.FrameDeclared = true
     getFrameDecl(m.initProc)
   
+  app(prc, initGCFrame(m.initProc))
+  
   app(prc, genSectionStart(cpsLocals))
   app(prc, m.initProc.s[cpsLocals])
   app(prc, genSectionEnd(cpsLocals))
@@ -842,6 +861,7 @@ proc genInitCode(m: BModule) =
   if optStackTrace in m.initProc.options and not m.PreventStackTrace:
     app(prc, deinitFrame(m.initProc))
   app(prc, genSectionEnd(cpsStmts))
+  app(prc, deinitGCFrame(m.initProc))
   appf(prc, "}$n$n")
   # we cannot simply add the init proc to ``m.s[cfsProcs]`` anymore because
   # that would lead to a *nesting* of merge sections which the merger does
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index 54e1f5d1a..ecbec664e 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -72,6 +72,8 @@ type
     receiveClosure*: PType    # closure record type that we get
     module*: BModule          # used to prevent excessive parameter passing
     withinLoop*: int          # > 0 if we are within a loop
+    gcFrameId*: natural       # for the GC stack marking
+    gcFrameType*: PRope       # the struct {} we put the GC markers into
   
   TTypeSeq* = seq[PType]
   TCGen = object of TPassContext # represents a C source file
diff --git a/compiler/commands.nim b/compiler/commands.nim
index f07361abe..14b943327 100755
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -207,7 +207,7 @@ proc addPathRec(dir: string, info: TLineInfo) =
 
 proc track(arg: string, info: TLineInfo) = 
   var a = arg.split(',')
-  if a.len != 3: LocalError(info, errTokenExpected, "FILE,LINE,COLMUN")
+  if a.len != 3: LocalError(info, errTokenExpected, "FILE,LINE,COLUMN")
   var line, column: int
   if parseUtils.parseInt(a[1], line) <= 0:
     LocalError(info, errInvalidNumber, a[1])
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index facb22432..b7548a4b5 100755
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -21,7 +21,8 @@ type
     hasSwitchRange,           # CC allows ranges in switch statements (GNU C)
     hasComputedGoto,          # CC has computed goto (GNU C extension)
     hasCpp,                   # CC is/contains a C++ compiler
-    hasAssume                 # CC has __assume (Visual C extension)
+    hasAssume,                # CC has __assume (Visual C extension)
+    hasGcGuard                # CC supports GC_GUARD to keep stack roots
   TInfoCCProps* = set[TInfoCCProp]
   TInfoCC* = tuple[
     name: string,        # the short name of the compiler
@@ -71,7 +72,7 @@ compiler gcc:
     debug: "",
     pic: "-fPIC",
     asmStmtFrmt: "asm($1);$n",
-    props: {hasSwitchRange, hasComputedGoto, hasCpp})
+    props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard})
     
 compiler gpp:
   result = gcc()
@@ -79,11 +80,10 @@ compiler gpp:
   result.name = "gpp"
   result.compilerExe = "g++"
   result.linkerExe = "g++"  
-  
-  result.debug.add " -g " # XXX: Why is this default for g++, but not for gcc?
 
-  result.buildDll = " -mdll" # XXX: Hmm, I'm keeping this from the previos version, 
-                             # but my gcc doesn't even have such an option (is this mingw?)
+  result.buildDll = " -mdll" 
+  # XXX: Hmm, I'm keeping this from the previos version, 
+  # but my gcc doesn't even have such an option (is this mingw?)
 
 compiler llvmGcc:
   result = gcc()
@@ -422,6 +422,13 @@ proc getOptSize(c: TSystemCC): string =
   if result == "": 
     result = cc[c].optSize    # use default settings from this file
 
+proc noAbsolutePaths: bool {.inline.} =
+  # We used to check current OS != specified OS, but this makes no sense
+  # really: Cross compilation from Linux to Linux for example is entirely
+  # reasonable.
+  # `optGenMapping` is included here for niminst.
+  result = gGlobalOptions * {optGenScript, optGenMapping} != {}
+
 const 
   specialFileA = 42
   specialFileB = 42
@@ -461,7 +468,7 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
     add(options, ' ' & cc[c].pic)
   
   var includeCmd, compilePattern: string
-  if targetOS == platform.hostOS: 
+  if not noAbsolutePaths(): 
     # compute include paths:
     includeCmd = cc[c].includeCmd & quoteIfContainsWhite(libpath)
 
@@ -474,9 +481,8 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
     compilePattern = cc[c].compilerExe
   
   # XXX fix the grammar finally, we need multi-line if expressions:
-  var cfile = if targetOS == platform.hostOS: cfilename else: extractFileName(
-                                                                     cfilename)
-  var objfile = if not isExternal or targetOS != platform.hostOS: toObjFile(
+  var cfile = if noAbsolutePaths(): extractFileName(cfilename) else: cfilename
+  var objfile = if not isExternal or noAbsolutePaths(): toObjFile(
                       cfile) else: completeCFilePath(toObjFile(cfile))
   cfile = quoteIfContainsWhite(AddFileExt(cfile, cExt))
   objfile = quoteIfContainsWhite(objfile)
@@ -532,9 +538,10 @@ proc CallCCompiler*(projectfile: string) =
     var it = PStrEntry(toLink.head)
     var objfiles = ""
     while it != nil:
+      let objFile = if noAbsolutePaths(): it.data.extractFilename else: it.data
       add(objfiles, ' ')
       add(objfiles, quoteIfContainsWhite(
-          addFileExt(it.data, cc[ccompiler].objExt)))
+          addFileExt(objFile, cc[ccompiler].objExt)))
       it = PStrEntry(it.next)
 
     if optGenStaticLib in gGlobalOptions:
@@ -545,18 +552,18 @@ proc CallCCompiler*(projectfile: string) =
       var linkerExe = getConfigVar(cc[c].name & ".linkerexe")
       if len(linkerExe) == 0: linkerExe = cc[c].linkerExe
       if targetOS == osWindows: linkerExe = addFileExt(linkerExe, "exe")
-      if platform.hostOS != targetOS: linkCmd = quoteIfContainsWhite(linkerExe)
+      if noAbsolutePaths(): linkCmd = quoteIfContainsWhite(linkerExe)
       else: linkCmd = quoteIfContainsWhite(JoinPath(ccompilerpath, linkerExe))
       if optGenGuiApp in gGlobalOptions: buildGui = cc[c].buildGui
       else: buildGui = ""
       var exefile: string
       if optGenDynLib in gGlobalOptions:
-        exefile = platform.os[targetOS].dllFrmt % [splitFile(projectFile).name]
+        exefile = platform.os[targetOS].dllFrmt % splitFile(projectFile).name
         buildDll = cc[c].buildDll
       else:
         exefile = splitFile(projectFile).name & platform.os[targetOS].exeExt
         buildDll = ""
-      if targetOS == platform.hostOS:
+      if not noAbsolutePaths():
         exefile = joinPath(splitFile(projectFile).dir, exefile)
       exefile = quoteIfContainsWhite(exefile)
       for linkedLib in items(cLinkedLibs):
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index 61b8ead4c..b2ae0d843 100755
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -53,7 +53,7 @@ proc CloseScope*(tab: var TSymTab) =
   var it: TTabIter
   var s = InitTabIter(it, tab.stack[tab.tos-1])
   while s != nil:
-    if sfForward in s.flags: 
+    if sfForward in s.flags:
       LocalError(s.info, errImplOfXexpected, getSymRepr(s))
     elif {sfUsed, sfExported} * s.flags == {} and optHints in s.options: 
       # BUGFIX: check options in s!
@@ -68,7 +68,10 @@ proc AddSym*(t: var TStrTable, n: PSym) =
 proc addDecl*(c: PContext, sym: PSym) = 
   if SymTabAddUnique(c.tab, sym) == Failure: 
     LocalError(sym.info, errAttemptToRedefine, sym.Name.s)
-  
+
+proc addPrelimDecl*(c: PContext, sym: PSym) =
+  discard SymTabAddUnique(c.tab, sym)
+
 proc addDeclAt*(c: PContext, sym: PSym, at: Natural) = 
   if SymTabAddUniqueAt(c.tab, sym, at) == Failure: 
     LocalError(sym.info, errAttemptToRedefine, sym.Name.s)
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index ff153c1c2..50afd47f9 100755
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -92,7 +92,8 @@ type
     errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX, 
     errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument, 
     errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate, 
-    errXhasSideEffects, errIteratorExpected, errLetNeedsInit, errWrongSymbolX,
+    errXhasSideEffects, errIteratorExpected, errLetNeedsInit,
+    errThreadvarCannotInit, errWrongSymbolX,
     errUser,
     warnCannotOpenFile, 
     warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit, 
@@ -321,6 +322,7 @@ const
     errXhasSideEffects: "\'$1\' can have side effects", 
     errIteratorExpected: "iterator within for loop context expected",
     errLetNeedsInit: "'let' symbol requires an initialization",
+    errThreadvarCannotInit: "a thread var cannot be initialized explicitly",
     errWrongSymbolX: "usage of \'$1\' is a user-defined error", 
     errUser: "$1", 
     warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",
@@ -342,7 +344,7 @@ const
     warnWriteToForeignHeap: "write to foreign heap [WriteToForeignHeap]",
     warnUser: "$1 [User]", 
     hintSuccess: "operation successful [Success]", 
-    hintSuccessX: "operation successful ($1 lines compiled; $2 sec total) [SuccessX]", 
+    hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]", 
     hintLineTooLong: "line too long [LineTooLong]", 
     hintXDeclaredButNotUsed: "\'$1\' is declared but not used [XDeclaredButNotUsed]", 
     hintConvToBaseNotNeeded: "conversion to base object is not needed [ConvToBaseNotNeeded]", 
diff --git a/compiler/nimrod.nim b/compiler/nimrod.nim
index 24dbc0617..a6918ce63 100755
--- a/compiler/nimrod.nim
+++ b/compiler/nimrod.nim
@@ -61,9 +61,9 @@ proc prependCurDir(f: string): string =
   else:
     result = f
 
-proc HandleCmdLine() = 
+proc HandleCmdLine() =
   var start = epochTime()
-  if paramCount() == 0: 
+  if paramCount() == 0:
     writeCommandLineUsage()
   else:
     # Process command line arguments:
@@ -85,13 +85,15 @@ proc HandleCmdLine() =
     ProcessCmdLine(passCmd2)
     MainCommand()
     if gVerbosity >= 2: echo(GC_getStatistics())
+    #echo(GC_getStatistics())
     if msgs.gErrorCounter == 0:
       when hasTinyCBackend:
         if gCmd == cmdRun:
           tccgen.run()
-      if gCmd notin {cmdInterpret, cmdRun}: 
-        rawMessage(hintSuccessX, [$gLinesCompiled, 
-                   formatFloat(epochTime() - start, ffDecimal, 3)])
+      if gCmd notin {cmdInterpret, cmdRun}:
+        rawMessage(hintSuccessX, [$gLinesCompiled,
+                   formatFloat(epochTime() - start, ffDecimal, 3),
+                   formatSize(getTotalMem())])
       if optRun in gGlobalOptions:
         var ex = quoteIfContainsWhite(
             changeFileExt(gProjectFull, "").prependCurDir)
diff --git a/compiler/parser.nim b/compiler/parser.nim
index e3bf3a748..ab715f029 100755
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -263,15 +263,16 @@ proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
     optInd(p, a)
   eat(p, endTok)
 
+proc newDotExpr(p: var TParser, a: PNode): PNode =
+  getTok(p)
+  optInd(p, a)
+  result = newNodeI(nkDotExpr, a.info)
+  addSon(result, a)
+  addSon(result, parseSymbol(p))
+
 proc qualifiedIdent(p: var TParser): PNode = 
   result = parseSymbol(p)     #optInd(p, result);
-  if p.tok.tokType == tkDot: 
-    getTok(p)
-    optInd(p, result)
-    var a = result
-    result = newNodeI(nkDotExpr, a.info)
-    addSon(result, a)
-    addSon(result, parseSymbol(p))
+  if p.tok.tokType == tkDot: result = newDotExpr(p, result)
 
 proc qualifiedIdentListAux(p: var TParser, endTok: TTokType, result: PNode) = 
   getTok(p)
@@ -465,13 +466,8 @@ proc primary(p: var TParser): PNode =
       result = newNodeP(nkCall, p)
       addSon(result, a)
       exprColonEqExprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result)
-    of tkDot: 
-      var a = result
-      result = newNodeP(nkDotExpr, p)
-      addSon(result, a)
-      getTok(p)               # skip '.'
-      optInd(p, result)
-      addSon(result, parseSymbol(p))
+    of tkDot:
+      result = newDotExpr(p, result)
       result = parseGStrLit(p, result)
     of tkBracketLe: 
       result = indexExprList(p, result, nkBracketExpr, tkBracketRi)
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index a291d4741..9877d4c52 100755
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -147,9 +147,6 @@ proc processMagic(c: PContext, n: PNode, s: PSym) =
       s.magic = m
       break
   if s.magic == mNone: Message(n.info, warnUnknownMagic, v)
-  # magics don't need an implementation, so we
-  # treat them as imported, instead of modifing a lot of working code:
-  incl(s.flags, sfImportc)
 
 proc wordToCallConv(sw: TSpecialWord): TCallingConvention = 
   # this assumes that the order of special words and calling conventions is
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index a81347eda..216b5674d 100755
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -144,13 +144,15 @@ proc semGenericStmt(c: PContext, n: PNode,
     var L = sonsLen(n)
     openScope(c.tab)
     n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, toBind)
-    for i in countup(0, L - 3): addDecl(c, newSymS(skUnknown, n.sons[i], c))
+    for i in countup(0, L - 3):
+      addPrelimDecl(c, newSymS(skUnknown, n.sons[i], c))
     n.sons[L - 1] = semGenericStmt(c, n.sons[L-1], flags, toBind)
     closeScope(c.tab)
   of nkBlockStmt, nkBlockExpr, nkBlockType: 
     checkSonsLen(n, 2)
     openScope(c.tab)
-    if n.sons[0].kind != nkEmpty: addDecl(c, newSymS(skUnknown, n.sons[0], c))
+    if n.sons[0].kind != nkEmpty: 
+      addPrelimDecl(c, newSymS(skUnknown, n.sons[0], c))
     n.sons[1] = semGenericStmt(c, n.sons[1], flags, toBind)
     closeScope(c.tab)
   of nkTryStmt: 
@@ -174,7 +176,7 @@ proc semGenericStmt(c: PContext, n: PNode,
                                    toBind)
       a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, toBind)
       for j in countup(0, L-3):
-        addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
+        addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
   of nkGenericParams: 
     for i in countup(0, sonsLen(n) - 1): 
       var a = n.sons[i]
@@ -185,14 +187,14 @@ proc semGenericStmt(c: PContext, n: PNode,
                                    toBind) 
       # do not perform symbol lookup for default expressions 
       for j in countup(0, L-3): 
-        addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
+        addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
   of nkConstSection: 
     for i in countup(0, sonsLen(n) - 1): 
       var a = n.sons[i]
       if a.kind == nkCommentStmt: continue 
       if (a.kind != nkConstDef): IllFormedAst(a)
       checkSonsLen(a, 3)
-      addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
+      addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
       a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, toBind)
       a.sons[2] = semGenericStmt(c, a.sons[2], flags, toBind)
   of nkTypeSection: 
@@ -201,7 +203,7 @@ proc semGenericStmt(c: PContext, n: PNode,
       if a.kind == nkCommentStmt: continue 
       if (a.kind != nkTypeDef): IllFormedAst(a)
       checkSonsLen(a, 3)
-      addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
+      addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
     for i in countup(0, sonsLen(n) - 1): 
       var a = n.sons[i]
       if a.kind == nkCommentStmt: continue 
@@ -240,17 +242,17 @@ proc semGenericStmt(c: PContext, n: PNode,
                                    toBind)
       a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, toBind)
       for j in countup(0, L-3): 
-        addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
+        addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
   of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, 
      nkIteratorDef, nkLambda: 
     checkSonsLen(n, bodyPos + 1)
-    addDecl(c, newSymS(skUnknown, getIdentNode(n.sons[0]), c))
+    addPrelimDecl(c, newSymS(skUnknown, getIdentNode(n.sons[0]), c))
     openScope(c.tab)
     n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos], 
                                               flags, toBind)
     if n.sons[paramsPos].kind != nkEmpty: 
       if n.sons[paramsPos].sons[0].kind != nkEmpty: 
-        addDecl(c, newSym(skUnknown, getIdent("result"), nil))
+        addPrelimDecl(c, newSym(skUnknown, getIdent("result"), nil))
       n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, toBind)
     n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, toBind)
     var body: PNode
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 29bf48c19..d8336fc94 100755
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -269,7 +269,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
       if def != nil and def.kind != nkEmpty:
         # this is only needed for the evaluation pass:
         v.ast = def
-      if a.kind != nkVarTuple: 
+        if sfThread in v.flags: LocalError(def.info, errThreadvarCannotInit)
+      if a.kind != nkVarTuple:
         v.typ = typ
         b = newNodeI(nkIdentDefs, a.info)
         addSon(b, newSymNode(v))
@@ -733,7 +734,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
       n.sons[bodyPos] = ast.emptyNode
   else: 
     if proto != nil: LocalError(n.info, errImplOfXexpected, proto.name.s)
-    if {sfImportc, sfBorrow} * s.flags == {}: incl(s.flags, sfForward)
+    if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone: 
+      incl(s.flags, sfForward)
     elif sfBorrow in s.flags: semBorrow(c, n, s)
   sideEffectsCheck(c, s)
   closeScope(c.tab)           # close scope for parameters
@@ -800,7 +802,7 @@ proc evalInclude(c: PContext, n: PNode): PNode =
     var f = checkModuleName(n.sons[i])
     var fileIndex = f.fileInfoIdx
     if ContainsOrIncl(c.includedFiles, fileIndex): 
-      GlobalError(n.info, errRecursiveDependencyX, f)
+      GlobalError(n.info, errRecursiveDependencyX, f.shortenDir)
     addSon(result, semStmt(c, gIncludeFile(f)))
     Excl(c.includedFiles, fileIndex)
   
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 78a95c56b..b71f230eb 100755
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -781,7 +781,11 @@ proc semGenericConstraints(c: PContext, n: PNode, result: PType) =
     semGenericConstraints(c, n.sons[1], result)
     semGenericConstraints(c, n.sons[2], result)
   else:
-    result.addSon(semTypeNode(c, n, nil))
+    var x = semTypeNode(c, n, nil)
+    if x.kind in StructuralEquivTypes and sonsLen(x) == 0:
+      x = newConstraint(c, x.kind)
+      #echo "came here for: ", typeToString(x)
+    result.addSon(x)
 
 proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = 
   result = copyNode(n)
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index a6bde6e40..9a8f3cee1 100755
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -388,7 +388,8 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
   of tyGenericInst: 
     result = typeRel(mapping, lastSon(f), a)
   of tyGenericBody: 
-    result = typeRel(mapping, lastSon(f), a)
+    let ff = lastSon(f)
+    if ff != nil: result = typeRel(mapping, ff, a)
   of tyGenericInvokation: 
     assert(f.sons[0].kind == tyGenericBody)
     if a.kind == tyGenericInvokation: 
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index 86d91bc1c..971ff4d32 100755
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -10,7 +10,8 @@
 ## This file implements features required for IDE support.
 
 import 
-  lexer, idents, ast, astalgo, semdata, msgs, types, sigmatch, options
+  lexer, idents, ast, astalgo, semdata, msgs, types, sigmatch, options, 
+  renderer
 
 const
   sep = '\t'
@@ -150,27 +151,25 @@ proc suggestFieldAccess(c: PContext, n: PNode) =
     else:
       suggestOperations(c, n, typ)
 
-proc findClosestDot(n: PNode): PNode = 
-  if msgs.inCheckpoint(n.info) == cpExact: 
+proc findClosestDot(n: PNode): PNode =
+  if n.kind == nkDotExpr and msgs.inCheckpoint(n.info) == cpExact:
     result = n
-  elif n.kind notin {nkNone..nkNilLit}:
-    for i in 0.. <sonsLen(n):
-      if n.sons[i].kind == nkDotExpr:
-        result = findClosestDot(n.sons[i])
-        if result != nil: return
+  else:
+    for i in 0.. <safeLen(n):
+      result = findClosestDot(n.sons[i])
+      if result != nil: return
 
 const
   CallNodes = {nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit,
                nkMacroStmt}
 
 proc findClosestCall(n: PNode): PNode = 
-  if msgs.inCheckpoint(n.info) == cpExact: 
+  if n.kind in callNodes and msgs.inCheckpoint(n.info) == cpExact: 
     result = n
-  elif n.kind notin {nkNone..nkNilLit}:
-    for i in 0.. <sonsLen(n):
-      if n.sons[i].kind in callNodes:
-        result = findClosestCall(n.sons[i])
-        if result != nil: return
+  else:
+    for i in 0.. <safeLen(n):
+      result = findClosestCall(n.sons[i])
+      if result != nil: return
 
 proc findClosestSym(n: PNode): PNode = 
   if n.kind == nkSym and msgs.inCheckpoint(n.info) == cpExact: 
diff --git a/compiler/types.nim b/compiler/types.nim
index d3f2bd1b5..8bce4fc5f 100755
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -277,7 +277,7 @@ proc analyseObjectWithTypeField(t: PType): TTypeFieldResult =
   result = analyseObjectWithTypeFieldAux(t, marker)
 
 proc isGBCRef(t: PType): bool = 
-  result = t.kind in {tyRef, tySequence, tyString}
+  result = t.kind in GcTypeKinds
 
 proc containsGarbageCollectedRef(typ: PType): bool = 
   # returns true if typ contains a reference, sequence or string (all the