summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim6
-rw-r--r--compiler/ccgcalls.nim76
-rw-r--r--compiler/ccgexprs.nim33
-rw-r--r--compiler/ccgstmts.nim14
-rw-r--r--compiler/ccgtypes.nim96
-rw-r--r--compiler/cgen.nim34
-rw-r--r--compiler/evaltempl.nim2
-rw-r--r--compiler/jsgen.nim11
-rw-r--r--compiler/lambdalifting.nim6
-rw-r--r--compiler/lookups.nim15
-rw-r--r--compiler/nimsuggest/nimsuggest.nim.cfg1
-rw-r--r--compiler/parampatterns.nim2
-rw-r--r--compiler/parser.nim5
-rw-r--r--compiler/pragmas.nim4
-rw-r--r--compiler/sem.nim26
-rw-r--r--compiler/semasgn.nim2
-rw-r--r--compiler/semcall.nim2
-rw-r--r--compiler/semdata.nim3
-rw-r--r--compiler/semexprs.nim5
-rw-r--r--compiler/semfields.nim2
-rw-r--r--compiler/semgnrc.nim52
-rw-r--r--compiler/semstmts.nim5
-rw-r--r--compiler/semtempl.nim10
-rw-r--r--compiler/semtypes.nim3
-rw-r--r--compiler/sigmatch.nim12
-rw-r--r--compiler/suggest.nim23
-rw-r--r--compiler/vm.nim8
-rw-r--r--compiler/vmdef.nim1
28 files changed, 289 insertions, 170 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index d487b5380..f7c1a07ed 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -655,7 +655,6 @@ type
     locGlobalVar,             # location is a global variable
     locParam,                 # location is a parameter
     locField,                 # location is a record field
-    locArrayElem,             # location is an array element
     locExpr,                  # "location" is really an expression
     locProc,                  # location is a proc (an address of a procedure)
     locData,                  # location is a constant
@@ -669,14 +668,15 @@ type
     lfDynamicLib,             # link symbol to dynamic library
     lfExportLib,              # export symbol for dynamic library generation
     lfHeader,                 # include header file for symbol
-    lfImportCompilerProc      # ``importc`` of a compilerproc
+    lfImportCompilerProc,     # ``importc`` of a compilerproc
+    lfSingleUse               # no location yet and will only be used once
   TStorageLoc* = enum 
     OnUnknown,                # location is unknown (stack, heap or static)
     OnStack,                  # location is on hardware stack
     OnHeap                    # location is on heap or global
                               # (reference counting needed)
   TLocFlags* = set[TLocFlag]
-  TLoc*{.final.} = object     
+  TLoc* = object     
     k*: TLocKind              # kind of location
     s*: TStorageLoc
     flags*: TLocFlags         # location's flags
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index cb8dcc25b..ad9d18257 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -45,12 +45,20 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
         genAssignment(p, d, tmp, {}) # no need for deep copying
     else:
       app(pl, ~")")
-      if d.k == locNone: getTemp(p, typ.sons[0], d)
-      assert(d.t != nil)        # generate an assignment to d:
-      var list: TLoc
-      initLoc(list, locCall, d.t, OnUnknown)
-      list.r = pl
-      genAssignment(p, d, list, {}) # no need for deep copying
+      if p.module.compileToCpp and lfSingleUse in d.flags:
+        # do not generate spurious temporaries for C++! For C we're better off
+        # with them to prevent undefined behaviour and because the codegen
+        # is free to emit expressions multiple times!
+        d.k = locCall
+        d.r = pl
+        excl d.flags, lfSingleUse
+      else:
+        if d.k == locNone: getTemp(p, typ.sons[0], d)
+        assert(d.t != nil)        # generate an assignment to d:
+        var list: TLoc
+        initLoc(list, locCall, d.t, OnUnknown)
+        list.r = pl
+        genAssignment(p, d, list, {}) # no need for deep copying
   else:
     app(pl, ~");$n")
     line(p, cpsStmts, pl)
@@ -90,7 +98,8 @@ proc openArrayLoc(p: BProc, n: PNode): PRope =
       of tyOpenArray, tyVarargs, tyArray, tyArrayConstr:
         "($1)+($2), ($3)-($2)+1"
       of tyString, tySequence:
-        if skipTypes(n.typ, abstractInst).kind == tyVar:
+        if skipTypes(n.typ, abstractInst).kind == tyVar and
+            not compileToCpp(p.module):
           "(*$1)->data+($2), ($3)-($2)+1"
         else:
           "$1->data+($2), ($3)-($2)+1"
@@ -102,7 +111,8 @@ proc openArrayLoc(p: BProc, n: PNode): PRope =
     of tyOpenArray, tyVarargs:
       result = ropef("$1, $1Len0", [rdLoc(a)])
     of tyString, tySequence:
-      if skipTypes(n.typ, abstractInst).kind == tyVar:
+      if skipTypes(n.typ, abstractInst).kind == tyVar and
+            not compileToCpp(p.module):
         result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField(p)])
       else:
         result = ropef("$1->data, $1->$2", [a.rdLoc, lenField(p)])
@@ -123,10 +133,14 @@ proc genArg(p: BProc, n: PNode, param: PSym): PRope =
     var n = if n.kind != nkHiddenAddr: n else: n.sons[0]
     result = openArrayLoc(p, n)
   elif ccgIntroducedPtr(param):
-    initLocExpr(p, n, a)
+    initLocExprSingleUse(p, n, a)
     result = addrLoc(a)
+  elif p.module.compileToCpp and param.typ.kind == tyVar and 
+      n.kind == nkHiddenAddr:
+    initLocExprSingleUse(p, n.sons[0], a)
+    result = rdLoc(a)
   else:
-    initLocExpr(p, n, a)
+    initLocExprSingleUse(p, n, a)
     result = rdLoc(a)
 
 proc genArgNoParam(p: BProc, n: PNode): PRope =
@@ -134,7 +148,7 @@ proc genArgNoParam(p: BProc, n: PNode): PRope =
   if n.kind == nkStringToCString:
     result = genArgStringToCString(p, n)
   else:
-    initLocExpr(p, n, a)
+    initLocExprSingleUse(p, n, a)
     result = rdLoc(a)
 
 proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
@@ -274,26 +288,28 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): PRope =
   assert(typ.n.sons[i].kind == nkSym)
   # if the parameter is lying (tyVar) and thus we required an additional deref,
   # skip the deref:
+  var ri = ri[i]
+  while ri.kind == nkObjDownConv: ri = ri[0]
   if typ.sons[i].kind == tyVar:
-    let x = if ri[i].kind == nkHiddenAddr: ri[i][0] else: ri[i]
-    if x.kind in {nkHiddenDeref, nkDerefExpr}:
-      result = genArgNoParam(p, x[0])
-      result.app("->")
-    elif x.typ.kind in {tyVar, tyPtr}:
+    let x = if ri.kind == nkHiddenAddr: ri[0] else: ri
+    if x.typ.kind == tyPtr:
       result = genArgNoParam(p, x)
       result.app("->")
+    elif x.kind in {nkHiddenDeref, nkDerefExpr}:
+      result = genArgNoParam(p, x[0])
+      result.app("->")
     else:
       result = genArgNoParam(p, x)
       result.app(".")
   elif typ.sons[i].kind == tyPtr:
-    if ri.sons[i].kind in {nkAddr, nkHiddenAddr}:
-      result = genArgNoParam(p, ri.sons[i][0])
+    if ri.kind in {nkAddr, nkHiddenAddr}:
+      result = genArgNoParam(p, ri[0])
       result.app(".")
     else:
-      result = genArgNoParam(p, ri.sons[i])
+      result = genArgNoParam(p, ri)
       result.app("->")
   else:
-    result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym)
+    result = genArgNoParam(p, ri) #, typ.n.sons[i].sym)
     result.app(".")
 
 proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope =
@@ -367,12 +383,20 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
     # simpler version of 'fixupCall' that works with the pl+params combination:
     var typ = skipTypes(ri.sons[0].typ, abstractInst)
     if typ.sons[0] != nil:
-      if d.k == locNone: getTemp(p, typ.sons[0], d)
-      assert(d.t != nil)        # generate an assignment to d:
-      var list: TLoc
-      initLoc(list, locCall, d.t, OnUnknown)
-      list.r = pl
-      genAssignment(p, d, list, {}) # no need for deep copying
+      if p.module.compileToCpp and lfSingleUse in d.flags:
+        # do not generate spurious temporaries for C++! For C we're better off
+        # with them to prevent undefined behaviour and because the codegen
+        # is free to emit expressions multiple times!
+        d.k = locCall
+        d.r = pl
+        excl d.flags, lfSingleUse
+      else:
+        if d.k == locNone: getTemp(p, typ.sons[0], d)
+        assert(d.t != nil)        # generate an assignment to d:
+        var list: TLoc
+        initLoc(list, locCall, d.t, OnUnknown)
+        list.r = pl
+        genAssignment(p, d, list, {}) # no need for deep copying
     else:
       app(pl, ~";$n")
       line(p, cpsStmts, pl)
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 591b6d76f..bd116d6fb 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -215,6 +215,7 @@ proc asgnComplexity(n: PNode): int =
     else: discard
 
 proc optAsgnLoc(a: TLoc, t: PType, field: PRope): TLoc =
+  assert field != nil
   result.k = locField
   result.s = a.s
   result.t = t
@@ -229,7 +230,7 @@ proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
       flags - {needToCopy}
     else:
       flags
-  let t = skipTypes(dest.t, abstractInst)
+  let t = skipTypes(dest.t, abstractInst).getUniqueType()
   for i in 0 .. <t.len:
     let t = t.sons[i]
     let field = ropef("Field$1", i.toRope)
@@ -336,6 +337,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
     elif needsComplexAssignment(ty):
       if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4:
         discard getTypeDesc(p.module, ty)
+        ty = getUniqueType(ty)
         internalAssert ty.n != nil
         genOptAsgnObject(p, dest, src, flags, ty.n)
       else:
@@ -660,9 +662,13 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
               ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8),
                     getSimpleTypeDesc(p.module, e.typ)]))
 
+proc isCppRef(p: BProc; typ: PType): bool {.inline.} =
+  result = p.module.compileToCpp and
+      skipTypes(typ, abstractInst).kind == tyVar
+
 proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
   let mt = mapType(e.sons[0].typ)
-  if mt in {ctArray, ctPtrToArray} and not enforceDeref:
+  if (mt in {ctArray, ctPtrToArray} and not enforceDeref):
     # XXX the amount of hacks for C's arrays is incredible, maybe we should
     # simply wrap them in a struct? --> Losing auto vectorization then?
     #if e[0].kind != nkBracketExpr:
@@ -670,12 +676,15 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
     expr(p, e.sons[0], d)
   else:
     var a: TLoc
-    initLocExpr(p, e.sons[0], a)
+    initLocExprSingleUse(p, e.sons[0], a)
     case skipTypes(a.t, abstractInst).kind
     of tyRef:
       d.s = OnHeap
     of tyVar:
       d.s = OnUnknown
+      if p.module.compileToCpp:
+        putIntoDest(p, d, e.typ, rdLoc(a))
+        return
     of tyPtr:
       d.s = OnUnknown         # BUGFIX!
     else: internalError(e.info, "genDeref " & $a.t.kind)
@@ -696,7 +705,7 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) =
     initLocExpr(p, e.sons[0], a)
     putIntoDest(p, d, e.typ, con("&", a.r))
     #Message(e.info, warnUser, "HERE NEW &")
-  elif mapType(e.sons[0].typ) == ctArray:
+  elif mapType(e.sons[0].typ) == ctArray or isCppRef(p, e.sons[0].typ):
     expr(p, e.sons[0], d)
   else:
     var a: TLoc
@@ -1120,7 +1129,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
   var r = rdLoc(tmp)
   if isRef:
     rawGenNew(p, tmp, nil)
-    t = t.sons[0].skipTypes(abstractInst)
+    t = t.lastSon.skipTypes(abstractInst)
     r = ropef("(*$1)", r)
     gcUsage(e)
   else:
@@ -1131,7 +1140,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
     var tmp2: TLoc
     tmp2.r = r
     var field: PSym = nil
-    var ty = t
+    var ty = getUniqueType(t)
     while ty != nil:
       field = lookupInRecord(ty.n, it.sons[0].sym.name)
       if field != nil: break
@@ -1201,9 +1210,9 @@ proc genNewFinalize(p: BProc, e: PNode) =
   appf(p.module.s[cfsTypeInit3], "$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
   b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [
       getTypeDesc(p.module, refType),
-      ti, getTypeDesc(p.module, skipTypes(refType.sons[0], abstractRange))])
+      ti, getTypeDesc(p.module, skipTypes(refType.lastSon, abstractRange))])
   genAssignment(p, a, b, {needToKeepAlive})  # set the object type:
-  bt = skipTypes(refType.sons[0], abstractRange)
+  bt = skipTypes(refType.lastSon, abstractRange)
   genObjectInit(p, cpsStmts, bt, a, false)
   gcUsage(e)
 
@@ -1234,7 +1243,8 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
   var t = skipTypes(a.t, abstractInst)
   while t.kind in {tyVar, tyPtr, tyRef}:
     if t.kind != tyVar: nilCheck = r
-    r = rfmt(nil, "(*$1)", r)
+    if t.kind != tyVar or not p.module.compileToCpp:
+      r = rfmt(nil, "(*$1)", r)
     t = skipTypes(t.lastSon, typedescInst)
   if not p.module.compileToCpp:
     while t.kind == tyObject and t.sons[0] != nil:
@@ -1861,7 +1871,8 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
     var t = skipTypes(a.t, abstractInst)
     while t.kind in {tyVar, tyPtr, tyRef}:
       if t.kind != tyVar: nilCheck = r
-      r = ropef("(*$1)", [r])
+      if t.kind != tyVar or not p.module.compileToCpp:
+        r = ropef("(*$1)", [r])
       t = skipTypes(t.lastSon, abstractInst)
     if not p.module.compileToCpp:
       while t.kind == tyObject and t.sons[0] != nil:
@@ -2071,8 +2082,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
     genAsgn(p, n, fastAsgn=p.prc != nil)
   of nkDiscardStmt:
     if n.sons[0].kind != nkEmpty:
-      var a: TLoc
       genLineDir(p, n)
+      var a: TLoc
       initLocExpr(p, n.sons[0], a)
   of nkAsmStmt: genAsmStmt(p, n)
   of nkTryStmt:
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index d7683f2c3..5d348c4e4 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -202,8 +202,19 @@ proc genSingleVar(p: BProc, a: PNode) =
       genVarPrototypeAux(generatedHeader, v)
     registerGcRoot(p, v)
   else:
+    let imm = isAssignedImmediately(a.sons[2])
+    if imm and p.module.compileToCpp:
+      # C++ really doesn't like things like 'Foo f; f = x' as that invokes a
+      # parameterless constructor followed by an assignment operator. So we
+      # generate better code here:
+      genLineDir(p, a)
+      let decl = localVarDecl(p, v)
+      var tmp: TLoc
+      initLocExprSingleUse(p, a.sons[2], tmp)
+      lineF(p, cpsStmts, "$# = $#;$n", decl, tmp.rdLoc)
+      return
     assignLocalVar(p, v)
-    initLocalVar(p, v, isAssignedImmediately(a.sons[2]))
+    initLocalVar(p, v, imm)
 
   if a.sons[2].kind != nkEmpty:
     genLineDir(targetProc, a)
@@ -932,6 +943,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
       var j = 0
       while x[j] in {' ', '\t'}: inc(j)
       if x[j] in {'"', ':'}:
+        # don't modify the line if already in quotes or
         # some clobber register list:
         app(result, x); app(result, tnl)
       elif x[j] != '\0':
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 90996d9cd..823e3bc1b 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -161,7 +161,13 @@ proc mapType(typ: PType): TCTypeKind =
 proc mapReturnType(typ: PType): TCTypeKind = 
   if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
   else: result = mapType(typ)
-  
+
+proc isImportedType(t: PType): bool = 
+  result = t.sym != nil and sfImportc in t.sym.flags
+
+proc isImportedCppType(t: PType): bool = 
+  result = t.sym != nil and sfInfixCall in t.sym.flags
+
 proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope
 proc needsComplexAssignment(typ: PType): bool = 
   result = containsGarbageCollectedRef(typ)
@@ -170,19 +176,20 @@ proc isObjLackingTypeField(typ: PType): bool {.inline.} =
   result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
       (typ.sons[0] == nil) or isPureObject(typ))
 
-proc isInvalidReturnType(rettype: PType): bool = 
+proc isInvalidReturnType(rettype: PType): bool =
   # Arrays and sets cannot be returned by a C procedure, because C is
   # such a poor programming language.
   # We exclude records with refs too. This enhances efficiency and
   # is necessary for proper code generation of assignments.
   if rettype == nil: result = true
-  else: 
+  else:
     case mapType(rettype)
-    of ctArray: 
+    of ctArray:
       result = not (skipTypes(rettype, typedescInst).kind in
           {tyVar, tyRef, tyPtr})
     of ctStruct:
       let t = skipTypes(rettype, typedescInst)
+      if rettype.isImportedCppType or t.isImportedCppType: return false
       result = needsComplexAssignment(t) or
           (t.kind == tyObject and not isObjLackingTypeField(t))
     else: result = false
@@ -297,12 +304,6 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
   else: app(params, ")")
   params = con("(", params)
 
-proc isImportedType(t: PType): bool = 
-  result = t.sym != nil and sfImportc in t.sym.flags
-
-proc isImportedCppType(t: PType): bool = 
-  result = t.sym != nil and sfInfixCall in t.sym.flags
-
 proc typeNameOrLiteral(t: PType, literal: string): PRope = 
   if (t.sym != nil) and (sfImportc in t.sym.flags) and (t.sym.magic == mNone): 
     result = getTypeName(t)
@@ -421,14 +422,18 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
     if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname])
     else: ae = sname
     fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
-    let fieldType = field.loc.t.skipTypes(abstractInst)
-    if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
-      appf(result, "$1 $2[SEQ_DECL_SIZE];$n",
-          [getTypeDescAux(m, fieldType.elemType, check), sname])
-    else:
-      # don't use fieldType here because we need the
-      # tyGenericInst for C++ template support
-      appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
+    # for importcpp'ed objects, we only need to set field.loc, but don't
+    # have to recurse via 'getTypeDescAux'. And not doing so prevents problems
+    # with heavily templatized C++ code:
+    if not isImportedCppType(rectype):
+      let fieldType = field.loc.t.skipTypes(abstractInst)
+      if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
+        appf(result, "$1 $2[SEQ_DECL_SIZE];$n",
+            [getTypeDescAux(m, fieldType.elemType, check), sname])
+      else:
+        # don't use fieldType here because we need the
+        # tyGenericInst for C++ template support
+        appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
   else: internalError(n.info, "genRecordFieldsAux()")
   
 proc getRecordFields(m: BModule, typ: PType, check: var IntSet): PRope = 
@@ -493,13 +498,15 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
   if t.sym != nil: useHeader(m, t.sym)
   result = getTypePre(m, t)
   if result != nil: return 
-  if containsOrIncl(check, t.id): 
+  if containsOrIncl(check, t.id):
+    if isImportedCppType(typ) or isImportedCppType(t): return
     internalError("cannot generate C type for: " & typeToString(typ)) 
     # XXX: this BUG is hard to fix -> we need to introduce helper structs,
     # but determining when this needs to be done is hard. We should split
     # C type generation into an analysis and a code generation phase somehow.
   case t.kind
   of tyRef, tyPtr, tyVar: 
+    let star = if t.kind == tyVar and compileToCpp(m): "&" else: "*"
     var et = t.lastSon
     var etB = et.skipTypes(abstractInst)
     if etB.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}: 
@@ -510,12 +517,12 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
     case etB.kind
     of tyObject, tyTuple:
       if isImportedCppType(etB) and et.kind == tyGenericInst:
-        result = con(getTypeDescAux(m, et, check), "*")
+        result = con(getTypeDescAux(m, et, check), star)
       else:
         # no restriction! We have a forward declaration for structs
         let x = getUniqueType(etB)
         let name = getTypeForward(m, x)
-        result = con(name, "*")
+        result = con(name, star)
         idTablePut(m.typeCache, t, result)
         pushType(m, x)
     of tySequence:
@@ -527,7 +534,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
       pushType(m, x)
     else:
       # else we have a strong dependency  :-(
-      result = con(getTypeDescAux(m, et, check), "*")
+      result = con(getTypeDescAux(m, et, check), star)
       idTablePut(m.typeCache, t, result)
   of tyOpenArray, tyVarargs:
     result = con(getTypeDescAux(m, t.sons[0], check), "*")
@@ -696,16 +703,7 @@ proc getNimNode(m: BModule): PRope =
   result = ropef("$1[$2]", [m.typeNodesName, toRope(m.typeNodes)])
   inc(m.typeNodes)
 
-when false:
-  proc getNimType(m: BModule): PRope = 
-    result = ropef("$1[$2]", [m.nimTypesName, toRope(m.nimTypes)])
-    inc(m.nimTypes)
-
-  proc allocMemTI(m: BModule, typ: PType, name: PRope) = 
-    var tmp = getNimType(m)
-    appf(m.s[cfsTypeInit2], "$2 = &$1;$n", [tmp, name])
-
-proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
+proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: PRope) =
   var nimtypeKind: int
   #allocMemTI(m, typ, name)
   if isObjLackingTypeField(typ):
@@ -715,6 +713,7 @@ proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
   
   var size: PRope
   if tfIncompleteStruct in typ.flags: size = toRope"void*"
+  elif m.compileToCpp: size = getTypeDesc(m, origType)
   else: size = getTypeDesc(m, typ)
   appf(m.s[cfsTypeInit3], 
        "$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n", 
@@ -730,13 +729,13 @@ proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
   appf(m.s[cfsVars], "TNimType $1; /* $2 */$n", 
        [name, toRope(typeToString(typ))])
 
-proc genTypeInfoAux(m: BModule, typ: PType, name: PRope) = 
+proc genTypeInfoAux(m: BModule, typ, origType: PType, name: PRope) = 
   var base: PRope
   if (sonsLen(typ) > 0) and (typ.sons[0] != nil): 
     base = genTypeInfo(m, typ.sons[0])
   else: 
     base = toRope("0")
-  genTypeInfoAuxBase(m, typ, name, base)
+  genTypeInfoAuxBase(m, typ, origType, name, base)
 
 proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope = 
   # bugfix: we need to search the type that contains the discriminator:
@@ -814,11 +813,12 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) =
         field.loc.r, genTypeInfo(m, field.typ), makeCString(field.name.s)])
   else: internalError(n.info, "genObjectFields")
   
-proc genObjectInfo(m: BModule, typ: PType, name: PRope) = 
-  if typ.kind == tyObject: genTypeInfoAux(m, typ, name)
-  else: genTypeInfoAuxBase(m, typ, name, toRope("0"))
+proc genObjectInfo(m: BModule, typ, origType: PType, name: PRope) = 
+  if typ.kind == tyObject: genTypeInfoAux(m, typ, origType, name)
+  else: genTypeInfoAuxBase(m, typ, origType, name, toRope("0"))
   var tmp = getNimNode(m)
-  genObjectFields(m, typ, typ.n, tmp)
+  if not isImportedCppType(typ):
+    genObjectFields(m, typ, typ.n, tmp)
   appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
   var t = typ.sons[0]
   while t != nil:
@@ -827,7 +827,7 @@ proc genObjectInfo(m: BModule, typ: PType, name: PRope) =
     t = t.sons[0]
 
 proc genTupleInfo(m: BModule, typ: PType, name: PRope) =
-  genTypeInfoAuxBase(m, typ, name, toRope("0"))
+  genTypeInfoAuxBase(m, typ, typ, name, toRope("0"))
   var expr = getNimNode(m)
   var length = sonsLen(typ)
   if length > 0: 
@@ -854,7 +854,7 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) =
   # optimizations here: The ``typ`` field is never set, as it is redundant
   # anyway. We generate a cstring array and a loop over it. Exceptional
   # positions will be reset after the loop.
-  genTypeInfoAux(m, typ, name)
+  genTypeInfoAux(m, typ, typ, name)
   var nodePtrs = getTempName()
   var length = sonsLen(typ.n)
   appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", 
@@ -894,13 +894,13 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) =
 
 proc genSetInfo(m: BModule, typ: PType, name: PRope) = 
   assert(typ.sons[0] != nil)
-  genTypeInfoAux(m, typ, name)
+  genTypeInfoAux(m, typ, typ, name)
   var tmp = getNimNode(m)
   appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n", 
        [tmp, toRope(firstOrd(typ)), name])
 
 proc genArrayInfo(m: BModule, typ: PType, name: PRope) = 
-  genTypeInfoAuxBase(m, typ, name, genTypeInfo(m, typ.sons[1]))
+  genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1]))
 
 proc fakeClosureType(owner: PSym): PType =
   # we generate the same RTTI as for a tuple[pointer, ref tuple[]]
@@ -946,23 +946,23 @@ proc genTypeInfo(m: BModule, t: PType): PRope =
   case t.kind
   of tyEmpty: result = toRope"0"
   of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
-    genTypeInfoAuxBase(m, t, result, toRope"0")
+    genTypeInfoAuxBase(m, t, t, result, toRope"0")
   of tyProc:
     if t.callConv != ccClosure:
-      genTypeInfoAuxBase(m, t, result, toRope"0")
+      genTypeInfoAuxBase(m, t, t, result, toRope"0")
     else:
       genTupleInfo(m, fakeClosureType(t.owner), result)
   of tySequence, tyRef:
-    genTypeInfoAux(m, t, result)
+    genTypeInfoAux(m, t, t, result)
     if gSelectedGC >= gcMarkAndSweep:
       let markerProc = genTraverseProc(m, t, tiNew)
       appf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
-  of tyPtr, tyRange: genTypeInfoAux(m, t, result)
+  of tyPtr, tyRange: genTypeInfoAux(m, t, t, result)
   of tyArrayConstr, tyArray: genArrayInfo(m, t, result)
   of tySet: genSetInfo(m, t, result)
   of tyEnum: genEnumInfo(m, t, result)
-  of tyObject: genObjectInfo(m, t, result)
-  of tyTuple: 
+  of tyObject: genObjectInfo(m, t, origType, result)
+  of tyTuple:
     # if t.n != nil: genObjectInfo(m, t, result)
     # else:
     # BUGFIX: use consistently RTTI without proper field names; otherwise
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 480c131ae..e16d5d0ce 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -402,11 +402,8 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
 
 proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = 
   inc(p.labels)
-  if gCmd == cmdCompileToLLVM: 
-    result.r = con("%LOC", toRope(p.labels))
-  else: 
-    result.r = con("LOC", toRope(p.labels))
-    linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
+  result.r = con("LOC", toRope(p.labels))
+  linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
   result.k = locTemp
   #result.a = - 1
   result.t = getUniqueType(t)
@@ -494,22 +491,26 @@ proc localDebugInfo(p: BProc, s: PSym) =
   inc(p.maxFrameLen)
   inc p.blocks[p.blocks.len-1].frameLen
 
-proc assignLocalVar(p: BProc, s: PSym) = 
-  #assert(s.loc.k == locNone) // not yet assigned
-  # this need not be fullfilled for inline procs; they are regenerated
-  # for each module that uses them!
+proc localVarDecl(p: BProc; s: PSym): PRope =
   if s.loc.k == locNone: 
     fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
     if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
-  var decl = getTypeDesc(p.module, s.loc.t)
+  result = getTypeDesc(p.module, s.loc.t)
   if s.constraint.isNil:
-    if sfRegister in s.flags: app(decl, " register")
+    if sfRegister in s.flags: app(result, " register")
     #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
     #  app(decl, " GC_GUARD")
-    if sfVolatile in s.flags: app(decl, " volatile")
-    appf(decl, " $1;$n", [s.loc.r])
+    if sfVolatile in s.flags: app(result, " volatile")
+    app(result, " ")
+    app(result, s.loc.r)
   else:
-    decl = ropef(s.cgDeclFrmt & ";$n", decl, s.loc.r)
+    result = ropef(s.cgDeclFrmt, result, s.loc.r)
+
+proc assignLocalVar(p: BProc, s: PSym) =
+  #assert(s.loc.k == locNone) // not yet assigned
+  # this need not be fullfilled for inline procs; they are regenerated
+  # for each module that uses them!
+  let decl = localVarDecl(p, s).con(";" & tnl)
   line(p, cpsLocals, decl)
   localDebugInfo(p, s)
 
@@ -586,6 +587,11 @@ proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
   initLoc(result, locNone, e.typ, OnUnknown)
   expr(p, e, result)
 
+proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) =
+  initLoc(result, locNone, e.typ, OnUnknown)
+  result.flags.incl lfSingleUse
+  expr(p, e, result)
+
 proc lenField(p: BProc): PRope =
   result = toRope(if p.module.compileToCpp: "len" else: "Sup.len")
 
diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim
index 946be68f8..29657a2ae 100644
--- a/compiler/evaltempl.nim
+++ b/compiler/evaltempl.nim
@@ -93,7 +93,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
     evalTemplateAux(body, args, ctx, result)
     if result.len == 1: result = result.sons[0]
     else:
-      globalError(result.info, errIllFormedAstX,
+      localError(result.info, errIllFormedAstX,
                   renderTree(result, {renderNoComments}))
   else:
     result = copyNode(body)
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index c48bf8c91..beb84b00a 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -1448,9 +1448,18 @@ proc genConv(p: PProc, n: PNode, r: var TCompRes) =
   var dest = skipTypes(n.typ, abstractVarRange)
   var src = skipTypes(n.sons[1].typ, abstractVarRange)
   gen(p, n.sons[1], r)
-  if (dest.kind != src.kind) and (src.kind == tyBool): 
+  if dest.kind == src.kind:
+    # no-op conversion
+    return
+  case dest.kind:
+  of tyBool:
     r.res = ropef("(($1)? 1:0)" | "toBool($#)", [r.res])
     r.kind = resExpr
+  of tyInt:
+    r.res = ropef("($1|0)", [r.res])
+  else:
+    # TODO: What types must we handle here?
+    discard
   
 proc upConv(p: PProc, n: PNode, r: var TCompRes) = 
   gen(p, n.sons[0], r)        # XXX
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index 6fa95fda2..b7dc277a4 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -719,7 +719,7 @@ proc outerProcSons(o: POuterContext, n: PNode, it: TIter) =
     let x = transformOuterProc(o, n.sons[i], it)
     if x != nil: n.sons[i] = x
 
-proc liftIterSym(n: PNode): PNode =
+proc liftIterSym(n: PNode; owner: PSym): PNode =
   # transforms  (iter)  to  (let env = newClosure[iter](); (iter, env))
   let iter = n.sym
   assert iter.kind == skClosureIterator
@@ -727,7 +727,7 @@ proc liftIterSym(n: PNode): PNode =
   result = newNodeIT(nkStmtListExpr, n.info, n.typ)
   
   let hp = getHiddenParam(iter)
-  let env = newSym(skLet, iter.name, iter.owner, iter.info)
+  let env = newSym(skLet, iter.name, owner, n.info)
   env.typ = hp.typ
   env.flags = hp.flags
   var v = newNodeI(nkVarSection, n.info)
@@ -867,7 +867,7 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
       # XXX why doesn't this work?
       var closure = PEnv(idTableGet(o.lambdasToEnv, local))
       if closure.isNil:
-        return liftIterSym(n)
+        return liftIterSym(n, o.fn)
       else:
         let createdVar = generateIterClosureCreation(o, closure,
                                                      closure.attachedNode)
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index 29be693dd..21d07f280 100644
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2012 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -22,7 +22,9 @@ proc considerQuotedIdent*(n: PNode): PIdent =
   of nkSym: result = n.sym.name
   of nkAccQuoted:
     case n.len
-    of 0: globalError(n.info, errIdentifierExpected, renderTree(n))
+    of 0:
+      localError(n.info, errIdentifierExpected, renderTree(n))
+      result = getIdent"<Error>"
     of 1: result = considerQuotedIdent(n.sons[0])
     else:
       var id = ""
@@ -31,12 +33,15 @@ proc considerQuotedIdent*(n: PNode): PIdent =
         case x.kind
         of nkIdent: id.add(x.ident.s)
         of nkSym: id.add(x.sym.name.s)
-        else: globalError(n.info, errIdentifierExpected, renderTree(n))
+        else:
+          localError(n.info, errIdentifierExpected, renderTree(n))
+          return getIdent"<Error>"
       result = getIdent(id)
   of nkOpenSymChoice, nkClosedSymChoice: result = n.sons[0].sym.name
   else:
-    globalError(n.info, errIdentifierExpected, renderTree(n))
- 
+    localError(n.info, errIdentifierExpected, renderTree(n))
+    result = getIdent"<Error>"
+
 template addSym*(scope: PScope, s: PSym) =
   strTableAdd(scope.symbols, s)
 
diff --git a/compiler/nimsuggest/nimsuggest.nim.cfg b/compiler/nimsuggest/nimsuggest.nim.cfg
index d1a1e6b62..062092f16 100644
--- a/compiler/nimsuggest/nimsuggest.nim.cfg
+++ b/compiler/nimsuggest/nimsuggest.nim.cfg
@@ -9,7 +9,6 @@ path:"$lib/packages/docutils"
 path:"$nim/compiler"
 
 define:useStdoutAsStdmsg
-symbol:nimsuggest
 define:nimsuggest
 
 cs:partial
diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim
index 300abea1e..8db786a25 100644
--- a/compiler/parampatterns.nim
+++ b/compiler/parampatterns.nim
@@ -41,7 +41,7 @@ type
 const
   MaxStackSize* = 64 ## max required stack size by the VM
 
-proc patternError(n: PNode) = 
+proc patternError(n: PNode) =
   localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
 
 proc add(code: var TPatternCode, op: TOpcode) {.inline.} =
diff --git a/compiler/parser.nim b/compiler/parser.nim
index adf3b72a3..aae0ce7f9 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -324,7 +324,10 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode =
       getTok(p)
     else:
       parMessage(p, errIdentifierExpected, p.tok)
-      getTok(p) # BUGFIX: We must consume a token here to prevent endless loops!
+      # BUGFIX: We must consume a token here to prevent endless loops!
+      # But: this really sucks for idetools and keywords, so we don't do it
+      # if it is a keyword:
+      if not isKeyword(p.tok.tokType): getTok(p)
       result = ast.emptyNode
 
 proc indexExpr(p: var TParser): PNode = 
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 735460906..90f87696b 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -447,7 +447,9 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
         addSon(result, newStrNode(nkStrLit, $marker))
       if c < 0: break 
       a = c + 1
-  else: illFormedAst(n)
+  else:
+    illFormedAstLocal(n)
+    result = newNode(nkAsmStmt, n.info)
   
 proc pragmaEmit(c: PContext, n: PNode) = 
   discard getStrLitNode(c, n)
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 90037fccd..214f471d6 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -47,6 +47,24 @@ proc finishMethod(c: PContext, s: PSym)
 
 proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode
 
+template semIdeForTemplateOrGenericCheck(n, requiresCheck) =
+  # we check quickly if the node is where the cursor is
+  when defined(nimsuggest):
+    if n.info.fileIndex == gTrackPos.fileIndex and n.info.line == gTrackPos.line:
+      requiresCheck = true
+
+template semIdeForTemplateOrGeneric(c: PContext; n: PNode;
+                                    requiresCheck: bool) =
+  # use only for idetools support; this is pretty slow so generics and
+  # templates perform some quick check whether the cursor is actually in
+  # the generic or template.
+  when defined(nimsuggest):
+    assert gCmd == cmdIdeTools
+    if requiresCheck:
+      if optIdeDebug in gGlobalOptions:
+        echo "passing to safeSemExpr: ", renderTree(n)
+      discard safeSemExpr(c, n)
+
 proc typeMismatch(n: PNode, formal, actual: PType) = 
   if formal.kind != tyError and actual.kind != tyError: 
     localError(n.info, errGenerated, msgKindToString(errTypeMismatch) &
@@ -359,13 +377,7 @@ proc semConstBoolExpr(c: PContext, n: PNode): PNode =
     localError(n.info, errConstExprExpected)
     result = nn
 
-type
-  TSemGenericFlag = enum
-    withinBind, withinTypeDesc, withinMixin
-  TSemGenericFlags = set[TSemGenericFlag]
-
-proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags,
-                    ctx: var IntSet): PNode
+proc semGenericStmt(c: PContext, n: PNode): PNode
 
 include semtypes, semtempl, semgnrc, semstmts, semexprs
 
diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim
index 0b68bc897..71ebbbafd 100644
--- a/compiler/semasgn.nim
+++ b/compiler/semasgn.nim
@@ -101,7 +101,7 @@ proc liftBodyObj(c: TLiftCtx; typ, x, y: PNode) =
   of nkRecList:
     for t in items(typ): liftBodyObj(c, t, x, y)
   else:
-    illFormedAst(typ)
+    illFormedAstLocal(typ)
 
 proc newAsgnCall(op: PSym; x, y: PNode): PNode =
   result = newNodeI(nkCall, x.info)
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index cdfdfc9d0..5cb713030 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -315,6 +315,8 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
     var r = resolveOverloads(c, n, nOrig, filter, errors)
     if r.state == csMatch: result = semResolvedCall(c, n, r)
     else:
+      # get rid of the deref again for a better error message:
+      n.sons[1] = n.sons[1].sons[0]
       notFoundError(c, n, errors)
   else: 
     notFoundError(c, n, errors)
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index bb82db292..157761591 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -307,6 +307,9 @@ proc markIndirect*(c: PContext, s: PSym) {.inline.} =
 proc illFormedAst*(n: PNode) =
   globalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
 
+proc illFormedAstLocal*(n: PNode) =
+  localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
+
 proc checkSonsLen*(n: PNode, length: int) = 
   if sonsLen(n) != length: illFormedAst(n)
   
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 34a9cd1dd..ab1b75994 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -956,9 +956,10 @@ proc makeDeref(n: PNode): PNode =
     t = skipTypes(t.sons[0], {tyGenericInst})
   while t.kind in {tyPtr, tyRef}:
     var a = result
-    result = newNodeIT(nkHiddenDeref, n.info, t.sons[0])
+    let baseTyp = t.lastSon
+    result = newNodeIT(nkHiddenDeref, n.info, baseTyp)
     addSon(result, a)
-    t = skipTypes(t.lastSon, {tyGenericInst})
+    t = skipTypes(baseTyp, {tyGenericInst})
 
 const
   tyTypeParamsHolders = {tyGenericInst, tyCompositeTypeClass}
diff --git a/compiler/semfields.nim b/compiler/semfields.nim
index f02c542ed..823bef225 100644
--- a/compiler/semfields.nim
+++ b/compiler/semfields.nim
@@ -98,7 +98,7 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
   of nkRecList:
     for t in items(typ): semForObjectFields(c, t, forLoop, father)
   else:
-    illFormedAst(typ)
+    illFormedAstLocal(typ)
 
 proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
   # so that 'break' etc. work as expected, we produce
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index d69fdb04a..13941fa58 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -25,10 +25,23 @@ proc getIdentNode(n: PNode): PNode =
   else:
     illFormedAst(n)
     result = n
-  
+
+type
+  GenericCtx = object
+    toMixin: IntSet
+    cursorInBody: bool # only for nimsuggest
+
+type
+  TSemGenericFlag = enum
+    withinBind, withinTypeDesc, withinMixin
+  TSemGenericFlags = set[TSemGenericFlag]
+
+proc semGenericStmt(c: PContext, n: PNode,
+                    flags: TSemGenericFlags, ctx: var GenericCtx): PNode
+
 proc semGenericStmtScope(c: PContext, n: PNode, 
                          flags: TSemGenericFlags,
-                         ctx: var IntSet): PNode = 
+                         ctx: var GenericCtx): PNode = 
   openScope(c)
   result = semGenericStmt(c, n, flags, ctx)
   closeScope(c)
@@ -37,7 +50,8 @@ template macroToExpand(s: expr): expr =
   s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfImmediate in s.flags)
 
 proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
-                          ctx: var IntSet): PNode =
+                          ctx: var GenericCtx): PNode =
+  semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
   incl(s.flags, sfUsed)
   case s.kind
   of skUnknown:
@@ -83,17 +97,17 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
     styleCheckUse(n.info, s)
 
 proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags, 
-            ctx: var IntSet): PNode =
+            ctx: var GenericCtx): PNode =
   result = n
   let ident = considerQuotedIdent(n)
   var s = searchInScopes(c, ident).skipAlias(n)
   if s == nil:
-    if ident.id notin ctx and withinMixin notin flags:
+    if ident.id notin ctx.toMixin and withinMixin notin flags:
       localError(n.info, errUndeclaredIdentifier, ident.s)
   else:
     if withinBind in flags:
       result = symChoice(c, n, s, scClosed)
-    elif s.name.id in ctx:
+    elif s.name.id in ctx.toMixin:
       result = symChoice(c, n, s, scForceOpen)
     else:
       result = semGenericStmtSymbol(c, n, s, ctx)
@@ -105,8 +119,10 @@ proc newDot(n, b: PNode): PNode =
   result.add(b)
 
 proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, 
-                 ctx: var IntSet; isMacro: var bool): PNode =
+                 ctx: var GenericCtx; isMacro: var bool): PNode =
   assert n.kind == nkDotExpr
+  semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
+
   let luf = if withinMixin notin flags: {checkUndeclared} else: {}
   
   var s = qualifiedLookUp(c, n, luf)
@@ -122,7 +138,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
       isMacro = s.kind in {skTemplate, skMacro}
       if withinBind in flags:
         result = newDot(result, symChoice(c, n, s, scClosed))
-      elif s.name.id in ctx:
+      elif s.name.id in ctx.toMixin:
         result = newDot(result, symChoice(c, n, s, scForceOpen))
       else:
         let sym = semGenericStmtSymbol(c, n, s, ctx)
@@ -137,9 +153,11 @@ proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
   styleCheckDef(n.info, s, kind)
 
 proc semGenericStmt(c: PContext, n: PNode, 
-                    flags: TSemGenericFlags, ctx: var IntSet): PNode =
+                    flags: TSemGenericFlags, ctx: var GenericCtx): PNode =
   result = n
-  if gCmd == cmdIdeTools: suggestStmt(c, n)
+  #if gCmd == cmdIdeTools: suggestStmt(c, n)
+  semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
+
   case n.kind
   of nkIdent, nkAccQuoted:
     result = lookup(c, n, flags, ctx)
@@ -162,14 +180,15 @@ proc semGenericStmt(c: PContext, n: PNode,
   of nkBind:
     result = semGenericStmt(c, n.sons[0], flags+{withinBind}, ctx)
   of nkMixinStmt:
-    result = semMixinStmt(c, n, ctx)
+    result = semMixinStmt(c, n, ctx.toMixin)
   of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit: 
     # check if it is an expression macro:
     checkMinSonsLen(n, 1)
     let fn = n.sons[0]
     var s = qualifiedLookUp(c, fn, {})
     if s == nil and withinMixin notin flags and
-        fn.kind in {nkIdent, nkAccQuoted} and considerQuotedIdent(fn).id notin ctx:
+        fn.kind in {nkIdent, nkAccQuoted} and 
+        considerQuotedIdent(fn).id notin ctx.toMixin:
       localError(n.info, errUndeclaredIdentifier, fn.renderTree)
     
     var first = 0
@@ -177,7 +196,7 @@ proc semGenericStmt(c: PContext, n: PNode,
     if s != nil:
       incl(s.flags, sfUsed)
       mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles}
-      let scOption = if s.name.id in ctx: scForceOpen else: scOpen
+      let scOption = if s.name.id in ctx.toMixin: scForceOpen else: scOpen
       case s.kind
       of skMacro:
         if macroToExpand(s):
@@ -377,4 +396,9 @@ proc semGenericStmt(c: PContext, n: PNode,
   else:
     for i in countup(0, sonsLen(n) - 1): 
       result.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
-  
+
+proc semGenericStmt(c: PContext, n: PNode): PNode =
+  var ctx: GenericCtx
+  ctx.toMixin = initIntset()
+  result = semGenericStmt(c, n, {}, ctx)
+  semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 565d4db06..3fe3e40f0 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1060,8 +1060,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     else:
       if s.typ.sons[0] != nil and kind notin skIterators:
         addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info))
-      var toBind = initIntSet()
-      n.sons[bodyPos] = semGenericStmtScope(c, n.sons[bodyPos], {}, toBind)
+      openScope(c)
+      n.sons[bodyPos] = semGenericStmt(c, n.sons[bodyPos])
+      closeScope(c)
       fixupInstantiatedSymbols(c, s)
     if sfImportc in s.flags:
       # so we just ignore the body after semantic checking for importc:
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index e2c46d3ab..3477d3d6f 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -105,10 +105,11 @@ proc replaceIdentBySym(n: var PNode, s: PNode) =
   else: illFormedAst(n)
 
 type
-  TemplCtx {.pure, final.} = object
+  TemplCtx = object
     c: PContext
     toBind, toMixin, toInject: IntSet
     owner: PSym
+    cursorInBody: bool # only for nimsuggest
 
 proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
   case n.kind
@@ -259,8 +260,9 @@ proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind; start=0) =
       addLocalDecl(c, a.sons[j], symKind)
 
 proc semPattern(c: PContext, n: PNode): PNode
-proc semTemplBody(c: var TemplCtx, n: PNode): PNode = 
+proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
   result = n
+  semIdeForTemplateOrGenericCheck(n, c.cursorInBody)
   case n.kind
   of nkIdent:
     if n.ident.id in c.toInject: return n
@@ -416,8 +418,9 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
     for i in countup(0, sonsLen(n) - 1):
       result.sons[i] = semTemplBody(c, n.sons[i])
 
-proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode = 
+proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
   result = n
+  semIdeForTemplateOrGenericCheck(n, c.cursorInBody)
   case n.kind
   of nkIdent:
     let s = qualifiedLookUp(c.c, n, {})
@@ -524,6 +527,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
   if s.typ.sons[0].kind notin {tyStmt, tyTypeDesc}:
     n.sons[bodyPos] = transformToExpr(n.sons[bodyPos]) 
     # only parameters are resolved, no type checking is performed
+  semIdeForTemplateOrGeneric(c, n.sons[bodyPos], ctx.cursorInBody)
   closeScope(c)
   popOwner()
   s.ast = n
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index da892dea8..8d1655593 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -1178,8 +1178,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
       return errorType(c)
     result = typeExpr.typ.base
     if result.isMetaType:
-      var toBind = initIntSet()
-      var preprocessed = semGenericStmt(c, n, {}, toBind)
+      var preprocessed = semGenericStmt(c, n)
       return makeTypeFromExpr(c, preprocessed)
   of nkIdent, nkAccQuoted:
     var s = semTypeIdent(c, n)
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 549f1f9ad..2e37f3bf1 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -1300,7 +1300,6 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
     # incorrect to simply use the first fitting match. However, to implement
     # this correctly is inefficient. We have to copy `m` here to be able to
     # roll back the side effects of the unification algorithm.
-
     let c = m.c
     var x, y, z: TCandidate
     initCandidate(c, x, m.callee)
@@ -1329,12 +1328,15 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
               y = z           # z is as good as x
     if x.state == csEmpty: 
       result = nil
-    elif (y.state == csMatch) and (cmpCandidates(x, y) == 0): 
+    elif y.state == csMatch and cmpCandidates(x, y) == 0: 
       if x.state != csMatch: 
         internalError(arg.info, "x.state is not csMatch") 
-      # ambiguous: more than one symbol fits
-      result = nil
-    else: 
+      # ambiguous: more than one symbol fits!
+      # See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match
+      # anyway:
+      if f.kind == tyExpr: result = arg
+      else: result = nil
+    else:
       # only one valid interpretation found:
       markUsed(arg.info, arg.sons[best].sym)
       styleCheckUse(arg.info, arg.sons[best].sym)
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index 7f8caca6e..6b168670c 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -256,19 +256,6 @@ proc findClosestSym(n: PNode): PNode =
       result = findClosestSym(n.sons[i])
       if result != nil: return
 
-proc safeSemExpr(c: PContext, n: PNode): PNode = 
-  try:
-    result = c.semExpr(c, n)
-  except ERecoverableError:
-    result = ast.emptyNode
-
-proc fuzzySemCheck(c: PContext, n: PNode): PNode = 
-  result = safeSemExpr(c, n)
-  if result == nil or result.kind == nkEmpty:
-    result = newNodeI(n.kind, n.info)
-    if n.kind notin {nkNone..nkNilLit}:
-      for i in 0 .. < sonsLen(n): result.addSon(fuzzySemCheck(c, n.sons[i]))
-
 var
   usageSym*: PSym
   lastLineInfo: TLineInfo
@@ -312,6 +299,13 @@ proc useSym*(sym: PSym): PNode =
   result = newSymNode(sym)
   markUsed(result.info, sym)
 
+proc safeSemExpr*(c: PContext, n: PNode): PNode =
+  # use only for idetools support!
+  try:
+    result = c.semExpr(c, n)
+  except ERecoverableError:
+    result = ast.emptyNode
+
 proc suggestExpr*(c: PContext, node: PNode) = 
   if nfIsCursor notin node.flags:
     if gTrackPos.line < 0: return
@@ -328,6 +322,9 @@ proc suggestExpr*(c: PContext, node: PNode) =
     if n.kind == nkDotExpr:
       var obj = safeSemExpr(c, n.sons[0])
       suggestFieldAccess(c, obj, outputs)
+      if optIdeDebug in gGlobalOptions:
+        echo "expression ", renderTree(obj), " has type ", typeToString(obj.typ)
+      #writeStackTrace()
     else:
       suggestEverything(c, n, outputs)
   
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 7edbb3fd2..b682b4e25 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -1364,9 +1364,11 @@ var
   globalCtx: PCtx
 
 proc setupGlobalCtx(module: PSym) =
-  if globalCtx.isNil: globalCtx = newCtx(module)
-  else: refresh(globalCtx, module)
-  registerAdditionalOps(globalCtx)
+  if globalCtx.isNil:
+    globalCtx = newCtx(module)
+    registerAdditionalOps(globalCtx)
+  else:
+    refresh(globalCtx, module)
 
 proc myOpen(module: PSym): PPassContext =
   #var c = newEvalContext(module, emRepl)
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index 3d49cb130..90b9f2517 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -213,6 +213,7 @@ proc newCtx*(module: PSym): PCtx =
 proc refresh*(c: PCtx, module: PSym) =
   c.module = module
   c.prc = PProc(blocks: @[])
+  c.loopIterations = MaxLoopIterations
 
 proc registerCallback*(c: PCtx; name: string; callback: VmCallback) =
   c.callbacks.add((name, callback))