summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim29
-rw-r--r--compiler/ccgexprs.nim4
-rw-r--r--compiler/ccgstmts.nim2
-rw-r--r--compiler/ccgthreadvars.nim4
-rw-r--r--compiler/ccgtrav.nim8
-rw-r--r--compiler/ccgtypes.nim3
-rw-r--r--compiler/cgen.nim19
-rw-r--r--compiler/cgendata.nim4
-rw-r--r--compiler/lambdalifting.nim7
-rw-r--r--compiler/parser.nim20
-rw-r--r--compiler/semdata.nim5
-rw-r--r--compiler/semexprs.nim17
-rw-r--r--compiler/seminst.nim132
-rw-r--r--compiler/semstmts.nim3
-rw-r--r--compiler/semtypes.nim292
-rw-r--r--compiler/sigmatch.nim64
-rw-r--r--compiler/types.nim79
17 files changed, 457 insertions, 235 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 514ab6a7c..bb015ea27 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -366,12 +366,8 @@ type
     tfFromGeneric,    # type is an instantiation of a generic; this is needed
                       # because for instantiations of objects, structural
                       # type equality has to be used
-    tfInstantiated,   # XXX: used to mark generic params after instantiation.
-                      # if the concrete type happens to be an implicit generic
-                      # this can lead to invalid proc signatures in the second
-                      # pass of semProcTypeNode performed after instantiation.
-                      # this won't be needed if we don't perform this redundant
-                      # second pass (stay tuned).
+    tfUnresolved,     # marks unresolved typedesc params: e.g.
+                      # proc foo(T: typedesc, list: seq[T]): var T
     tfRetType,        # marks return types in proc (used to detect type classes 
                       # used as return types for return type inference)
     tfAll,            # type class requires all constraints to be met (default)
@@ -690,6 +686,8 @@ type
                               # for record types a nkRecord node
                               # for enum types a list of symbols
                               # for tyInt it can be the int literal
+                              # for procs and tyGenericBody, it's the
+                              # formal param list
                               # else: unused
     destructor*: PSym         # destructor. warning: nil here may not necessary
                               # mean that there is no destructor.
@@ -794,6 +792,7 @@ const
   nkStrKinds* = {nkStrLit..nkTripleStrLit}
 
   skLocalVars* = {skVar, skLet, skForVar, skParam, skResult}
+  skProcKinds* = {skProc, skTemplate, skMacro, skIterator, skMethod, skConverter}
 
   lfFullExternalName* = lfParamCopy # \
     # only used when 'gCmd == cmdPretty': Indicates that the symbol has been
@@ -1053,8 +1052,8 @@ proc NewType(kind: TTypeKind, owner: PSym): PType =
   result.size = - 1
   result.align = 2            # default alignment
   result.id = getID()
-  when debugIds: 
-    RegisterId(result)        
+  when debugIds:
+    RegisterId(result)
   #if result.id < 2000 then
   #  MessageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
   
@@ -1091,7 +1090,6 @@ proc copyType(t: PType, owner: PSym, keepId: bool): PType =
   if keepId: 
     result.id = t.id
   else: 
-    result.id = getID()
     when debugIds: RegisterId(result)
   result.sym = t.sym          # backend-info should not be copied
   
@@ -1361,10 +1359,19 @@ proc getStrOrChar*(a: PNode): string =
 
 proc isGenericRoutine*(s: PSym): bool = 
   case s.kind
-  of skProc, skTemplate, skMacro, skIterator, skMethod, skConverter:
-    result = s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty
+  of skProcKinds:
+    result = sfFromGeneric in s.flags or
+             (s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty)
   else: nil
 
+proc skipGenericOwner*(s: PSym): PSym =
+  InternalAssert s.kind in skProcKinds
+  ## Generic instantiations are owned by their originating generic
+  ## symbol. This proc skips such owners and goes straigh to the owner
+  ## of the generic itself (the module or the enclosing proc).
+  result = if sfFromGeneric in s.flags: s.owner.owner
+           else: s.owner
+
 proc isRoutine*(s: PSym): bool {.inline.} =
   result = s.kind in {skProc, skTemplate, skMacro, skIterator, skMethod,
                       skConverter}
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index bb1035ab6..635756220 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1932,12 +1932,12 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
     nil
   of nkPragma: genPragma(p, n)
   of nkProcDef, nkMethodDef, nkConverterDef: 
-    if (n.sons[genericParamsPos].kind == nkEmpty): 
+    if (n.sons[genericParamsPos].kind == nkEmpty):
       var prc = n.sons[namePos].sym
       # due to a bug/limitation in the lambda lifting, unused inner procs
       # are not transformed correctly. We work around this issue (#411) here
       # by ensuring it's no inner proc (owner is a module):
-      if prc.owner.kind == skModule:
+      if prc.skipGenericOwner.kind == skModule:
         if (optDeadCodeElim notin gGlobalOptions and
             sfDeadCodeElim notin getModule(prc).flags) or
             ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 01c734524..6f362a615 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -152,7 +152,7 @@ proc genSingleVar(p: BProc, a: PNode) =
   var immediateAsgn = a.sons[2].kind != nkEmpty
   if sfGlobal in v.flags:
     if v.owner.kind != skModule:
-      targetProc = p.module.preInitProc
+      targetProc = p.module.postInitProc
     assignGlobalVar(targetProc, v)
     # XXX: be careful here.
     # Global variables should not be zeromem-ed within loops 
diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim
index 4785402e7..d312ea027 100644
--- a/compiler/ccgthreadvars.nim
+++ b/compiler/ccgthreadvars.nim
@@ -12,10 +12,10 @@
 
 # included from cgen.nim
 
-proc emulatedThreadVars(): bool {.inline.} =
+proc emulatedThreadVars(): bool =
   result = {optThreads, optTlsEmulation} <= gGlobalOptions
 
-proc AccessThreadLocalVar(p: BProc, s: PSym) =
+proc accessThreadLocalVar(p: BProc, s: PSym) =
   if emulatedThreadVars() and not p.ThreadVarAccessed:
     p.ThreadVarAccessed = true
     p.module.usesThreadVars = true
diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim
index aa8b85600..9534eae91 100644
--- a/compiler/ccgtrav.nim
+++ b/compiler/ccgtrav.nim
@@ -127,18 +127,22 @@ proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
   m.s[cfsProcHeaders].appf("$1;$n", header)
   m.s[cfsProcs].app(generatedProc)
 
-
 proc genTraverseProcForGlobal(m: BModule, s: PSym): PRope =
   discard genTypeInfo(m, s.loc.t)
   
   var c: TTraversalClosure
   var p = newProc(nil, m)
+  var sLoc = s.loc.r
   result = getGlobalTempName()
   
+  if sfThread in s.flags and emulatedThreadVars():
+    accessThreadLocalVar(p, s)
+    sLoc = con("NimTV->", sLoc)
+    
   c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
   c.p = p
   let header = ropef("N_NIMCALL(void, $1)()", result)
-  genTraverseProc(c, s.loc.r, s.loc.t)
+  genTraverseProc(c, sLoc, s.loc.t)
   
   let generatedProc = ropef("$1 {$n$2$3$4}$n",
         [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index bb9d4c3a1..4548ac641 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -437,8 +437,9 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
           app(result, genRecordFieldsAux(m, k, ae, rectype, check))
       else: internalError("genRecordFieldsAux(record case branch)")
     appf(result, "} $1;$n", [uname])
-  of nkSym: 
+  of nkSym:
     field = n.sym
+    if field.typ.kind == tyEmpty: return
     #assert(field.ast == nil)
     sname = mangleRecFieldName(field, rectype)
     if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname])
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 18f33f32a..0c3f2da84 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -284,6 +284,9 @@ proc genLineDir(p: BProc, t: PNode) =
     linefmt(p, cpsStmts, "nimln($1, $2);$n",
             line.toRope, t.info.quotedFilename)
 
+proc accessThreadLocalVar(p: BProc, s: PSym)
+proc emulatedThreadVars(): bool {.inline.}
+
 include "ccgtypes.nim"
 
 # ------------------------------ Manager of temporaries ------------------
@@ -858,8 +861,8 @@ proc isActivated(prc: PSym): bool = prc.typ != nil
 proc genProc(m: BModule, prc: PSym) = 
   if sfBorrow in prc.flags or not isActivated(prc): return
   fillProcLoc(prc)
-  if {sfForward, sfFromGeneric} * prc.flags != {}: addForwardedProc(m, prc)
-  else: 
+  if sfForward in prc.flags: addForwardedProc(m, prc)
+  else:
     genProcNoForward(m, prc)
     if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and
         generatedHeader != nil and lfNoDecl notin prc.loc.Flags:
@@ -1028,8 +1031,9 @@ proc genInitCode(m: BModule) =
   app(prc, initGCFrame(m.initProc))
  
   app(prc, genSectionStart(cpsLocals))
-  app(prc, m.initProc.s(cpsLocals))
   app(prc, m.preInitProc.s(cpsLocals))
+  app(prc, m.initProc.s(cpsLocals))
+  app(prc, m.postInitProc.s(cpsLocals))
   app(prc, genSectionEnd(cpsLocals))
 
   if optStackTrace in m.initProc.options and not m.FrameDeclared:
@@ -1045,11 +1049,13 @@ proc genInitCode(m: BModule) =
   app(prc, genSectionStart(cpsInit))
   app(prc, m.preInitProc.s(cpsInit))
   app(prc, m.initProc.s(cpsInit))
+  app(prc, m.postInitProc.s(cpsInit))
   app(prc, genSectionEnd(cpsInit))
 
   app(prc, genSectionStart(cpsStmts))
   app(prc, m.preInitProc.s(cpsStmts))
   app(prc, m.initProc.s(cpsStmts))
+  app(prc, m.postInitProc.s(cpsStmts))
   app(prc, genSectionEnd(cpsStmts))
   if optStackTrace in m.initProc.options and not m.PreventStackTrace:
     app(prc, deinitFrame(m.initProc))
@@ -1094,6 +1100,11 @@ proc newPreInitProc(m: BModule): BProc =
   # little hack so that unique temporaries are generated:
   result.labels = 100_000
 
+proc newPostInitProc(m: BModule): BProc =
+  result = newProc(nil, m)
+  # little hack so that unique temporaries are generated:
+  result.labels = 200_000
+
 proc rawNewModule(module: PSym, filename: string): BModule =
   new(result)
   InitLinkedList(result.headerFiles)
@@ -1108,6 +1119,7 @@ proc rawNewModule(module: PSym, filename: string): BModule =
   result.initProc = newProc(nil, result)
   result.initProc.options = gOptions
   result.preInitProc = newPreInitProc(result)
+  result.postInitProc = newPostInitProc(result)
   initNodeTable(result.dataCache)
   result.typeStack = @[]
   result.forwardedProcs = @[]
@@ -1128,6 +1140,7 @@ proc resetModule*(m: var BModule) =
   m.initProc = newProc(nil, m)
   m.initProc.options = gOptions
   m.preInitProc = newPreInitProc(m)
+  m.postInitProc = newPostInitProc(m)
   initNodeTable(m.dataCache)
   m.typeStack = @[]
   m.forwardedProcs = @[]
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index ad17194df..b5888d0f4 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -100,10 +100,8 @@ type
     headerFiles*: TLinkedList # needed headers to include
     typeInfoMarker*: TIntSet  # needed for generating type information
     initProc*: BProc          # code for init procedure
+    postInitProc*: BProc      # code to be executed after the init proc
     preInitProc*: BProc       # code executed before the init proc
-                              # used for initialization code for
-                              # .global. variables
-                              # (or instantiated generic variables)
     typeStack*: TTypeSeq      # used for type generation
     dataCache*: TNodeTable
     forwardedProcs*: TSymSeq  # keep forwarded procs here
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index 8d4946ab5..96eb3a5f4 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -219,8 +219,8 @@ proc getHiddenParam(routine: PSym): PSym =
   result = hidden.sym
 
 proc isInnerProc(s, outerProc: PSym): bool {.inline.} =
-  result = s.kind in {skProc, skMethod, skConverter} and
-    s.owner == outerProc and not isGenericRoutine(s)
+  result = s.kind in {skProc, skMethod, skConverter} and 
+           s.skipGenericOwner == outerProc
   #s.typ.callConv == ccClosure
 
 proc addClosureParam(i: PInnerContext, e: PEnv) =
@@ -288,6 +288,9 @@ proc interestingVar(s: PSym): bool {.inline.} =
 proc semCaptureSym*(s, owner: PSym) =
   if interestingVar(s) and owner.id != s.owner.id and s.kind != skResult:
     if owner.typ != nil and not isGenericRoutine(owner):
+      # XXX: is this really safe?
+      # if we capture a var from another generic routine,
+      # it won't be consider captured.
       owner.typ.callConv = ccClosure
     #echo "semCaptureSym ", owner.name.s, owner.id, " ", s.name.s, s.id
     # since the analysis is not entirely correct, we don't set 'tfCapturesEnv'
diff --git a/compiler/parser.nim b/compiler/parser.nim
index a92dde74f..699a50c62 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -627,6 +627,13 @@ proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
     getTok(p)  # we must consume a token here to prevend endless loops!
     result = ast.emptyNode
 
+proc namedParams(p: var TParser, callee: PNode,
+                 kind: TNodeKind, endTok: TTokType): PNode =
+  let a = callee
+  result = newNodeP(kind, p)
+  addSon(result, a)
+  exprColonEqExprListAux(p, endTok, result)
+
 proc primarySuffix(p: var TParser, r: PNode): PNode =
   #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
   #|               | doBlocks
@@ -636,11 +643,8 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
   result = r
   while p.tok.indent < 0:
     case p.tok.tokType
-    of tkParLe: 
-      var a = result
-      result = newNodeP(nkCall, p)
-      addSon(result, a)
-      exprColonEqExprListAux(p, tkParRi, result)
+    of tkParLe:
+      result = namedParams(p, result, nkCall, tkParRi)
       if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
         result.kind = nkObjConstr
       else:
@@ -653,10 +657,10 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
     of tkDot:
       result = dotExpr(p, result)
       result = parseGStrLit(p, result)
-    of tkBracketLe: 
-      result = indexExprList(p, result, nkBracketExpr, tkBracketRi)
+    of tkBracketLe:
+      result = namedParams(p, result, nkBracketExpr, tkBracketRi)
     of tkCurlyLe:
-      result = indexExprList(p, result, nkCurlyExpr, tkCurlyRi)
+      result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
     else: break
 
 proc primary(p: var TParser, mode: TPrimaryMode): PNode
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 72d5a5fef..b9c32a680 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -207,6 +207,11 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType =
 proc newTypeS(kind: TTypeKind, c: PContext): PType = 
   result = newType(kind, getCurrOwner())
 
+proc newTypeWithSons*(c: PContext, kind: TTypeKind,
+                      sons: seq[PType]): PType =
+  result = newType(kind, getCurrOwner())
+  result.sons = sons
+
 proc errorType*(c: PContext): PType =
   ## creates a type representing an error state
   result = newTypeS(tyError, c)
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 4591c3942..d88cc28b6 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -111,7 +111,11 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
     # var len = 0 # but won't be called
     # genericThatUsesLen(x) # marked as taking a closure?
   of skGenericParam:
-    if s.ast != nil: result = semExpr(c, s.ast)
+    if s.typ.kind == tyExpr:
+      result = newSymNode(s, n.info)
+      result.typ = s.typ.lastSon
+    elif s.ast != nil:
+      result = semExpr(c, s.ast)
     else:
       InternalError(n.info, "no default for")
       result = emptyNode
@@ -888,10 +892,13 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
       let tbody = ty.sons[0]
       for s in countup(0, tbody.len-2):
         let tParam = tbody.sons[s]
-        assert tParam.kind == tyGenericParam
         if tParam.sym.name == i:
-          let foundTyp = makeTypeDesc(c, ty.sons[s + 1])
-          return newSymNode(copySym(tParam.sym).linkTo(foundTyp), n.info)
+          let rawTyp = ty.sons[s + 1]
+          if rawTyp.kind == tyExpr:
+            return rawTyp.n
+          else:
+            let foundTyp = makeTypeDesc(c, rawTyp)
+            return newSymNode(copySym(tParam.sym).linkTo(foundTyp), n.info)
       return
     else:
       # echo "TYPE FIELD ACCESS"
@@ -1820,7 +1827,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkBind:
     Message(n.info, warnDeprecated, "bind")
     result = semExpr(c, n.sons[0], flags)
-  of nkTypeOfExpr:
+  of nkTypeOfExpr, nkTupleTy, nkRefTy..nkEnumTy:
     var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
     result = symNodeFromType(c, typ, n.info)
   of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: 
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 9dc99d173..601072833 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -38,7 +38,6 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
       #t = instGenericContainer(c, a, t)
       t = generateTypeInstance(c, pt, a, t)
       #t = ReplaceTypeVarsT(cl, t)
-    t.flags.incl tfInstantiated
     s.typ = t
     addDecl(c, s)
     entry.concreteTypes[i] = t
@@ -84,11 +83,20 @@ proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) =
   else:
     for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, symMap)
 
+proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind)
+
 proc instantiateBody(c: PContext, n: PNode, result: PSym) =
   if n.sons[bodyPos].kind != nkEmpty:
+    inc c.InGenericInst
     # add it here, so that recursive generic procs are possible:
     addDecl(c, result)
     pushProcCon(c, result)
+    # add params to scope
+    for i in 1 .. <result.typ.n.len:
+      var param = result.typ.n.sons[i].sym
+      param.owner = result
+      addParamOrResult(c, param, result.kind)
+    # debug result.typ.n
     maybeAddResult(c, result, n)
     var b = n.sons[bodyPos]
     var symMap: TIdTable
@@ -100,6 +108,7 @@ proc instantiateBody(c: PContext, n: PNode, result: PSym) =
     #echo "code instantiated ", result.name.s
     excl(result.flags, sfForward)
     popProcCon(c)
+    dec c.InGenericInst
 
 proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
   for i in countup(0, c.generics.len - 1):
@@ -109,8 +118,6 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
       openScope(c)
       var n = oldPrc.ast
       n.sons[bodyPos] = copyTree(s.getBody)
-      if n.sons[paramsPos].kind != nkEmpty: 
-        addParams(c, oldPrc.typ.n, oldPrc.kind)
       instantiateBody(c, n, oldPrc)
       closeScope(c)
       popInfoContext()
@@ -123,7 +130,98 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
       s.ast.sons[genericParamsPos].kind == nkEmpty:
     c.threadEntries.add(s)
 
-proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, 
+proc instGenericContainer(c: PContext, info: TLineInfo, header: PType): PType =
+  var cl: TReplTypeVars
+  InitIdTable(cl.symMap)
+  InitIdTable(cl.typeMap)
+  cl.info = info
+  cl.c = c
+  result = ReplaceTypeVarsT(cl, header)
+
+proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
+  result = instGenericContainer(c, n.info, header)
+
+proc fixupProcType(c: PContext, genericType: PType,
+                   inst: TInstantiation): PType =
+  # XXX: This is starting to look suspiciously like ReplaceTypeVarsT
+  # there are few apparent differences, but maybe the code could be
+  # moved over.
+  # * the code here uses the new genericSym.position property when
+  #   doing lookups. 
+  # * the handling of tyTypeDesc seems suspicious in ReplaceTypeVarsT
+  #   typedesc params were previously handled in the second pass of
+  #   semParamList
+  # * void (nkEmpty) params doesn't seem to be stripped in ReplaceTypeVarsT
+  result = genericType
+  if result == nil: return
+
+  case genericType.kind
+  of tyGenericParam, tyTypeClass:
+    result = inst.concreteTypes[genericType.sym.position]
+  of tyTypeDesc:
+    result = inst.concreteTypes[genericType.sym.position]
+    if tfUnresolved in genericType.flags:
+      result = result.sons[0]
+  of tyExpr:
+    result = inst.concreteTypes[genericType.sym.position]
+  of tyOpenArray, tyArray, tySet, tySequence, tyTuple, tyProc,
+     tyPtr, tyVar, tyRef, tyOrdinal, tyRange, tyVarargs:
+    if genericType.sons == nil: return
+    var head = 0
+    for i in 0 .. <genericType.sons.len:
+      let origType = genericType.sons[i]
+      var changed = fixupProcType(c, origType, inst)
+      if changed != genericType.sons[i]:
+        var changed = changed.skipIntLit
+        if result == genericType:
+          # the first detected change initializes the result
+          result = copyType(genericType, genericType.owner, false)
+          if genericType.n != nil:
+            result.n = copyTree(genericType.n)
+
+        # XXX: doh, we have to treat seq and arrays as special case
+        # because sometimes the `@` magic will be applied to an empty
+        # sequence having the type tySequence(tyEmpty)
+        if changed.kind == tyEmpty and
+           genericType.kind notin {tyArray, tySequence}:
+          if genericType.kind == tyProc and i == 0:
+            # return types of procs are overwritten with nil
+            changed = nil
+          else:
+            # otherwise, `empty` is just erased from the signature
+            result.sons[i..i] = []
+            if result.n != nil: result.n.sons[i..i] = []
+            continue
+        
+        result.sons[head] = changed
+        
+        if result.n != nil:
+          if result.n.kind == nkRecList:
+            for son in result.n.sons:
+              if son.typ == origType:
+                son.typ = changed
+                son.sym = copySym(son.sym, true)
+                son.sym.typ = changed
+          if result.n.kind == nkFormalParams:
+            if i != 0:
+              let origParam = result.n.sons[head].sym
+              var param = copySym(origParam)
+              param.typ = changed
+              param.ast = origParam.ast
+              result.n.sons[head] = newSymNode(param)
+
+      # won't be advanced on empty (void) nodes
+      inc head
+  
+  of tyGenericInvokation:
+    result = newTypeWithSons(c, tyGenericInvokation, genericType.sons)
+    for i in 1 .. <genericType.sons.len:
+      result.sons[i] = fixupProcType(c, result.sons[i], inst)
+    result = instGenericContainer(c, getInfoContext(-1), result)
+  
+  else: nil
+
+proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
                       info: TLineInfo): PSym =
   # no need to instantiate generic templates/macros:
   if fn.kind in {skTemplate, skMacro}: return fn
@@ -137,11 +235,11 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   # we set the friend module:
   var oldFriend = c.friendModule
   c.friendModule = getModule(fn)
+  #let oldScope = c.currentScope
+  #c.currentScope = fn.scope
   result = copySym(fn, false)
   incl(result.flags, sfFromGeneric)
-  # keep the owner if it's an inner proc (for proper closure transformations):
-  if fn.owner.kind == skModule:
-    result.owner = getCurrOwner().owner
+  result.owner = fn
   result.ast = n
   pushOwner(result)
   openScope(c)
@@ -152,16 +250,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   var entry = TInstantiation.new
   entry.sym = result
   instantiateGenericParamList(c, n.sons[genericParamsPos], pt, entry[])
+  result.typ = fixupProcType(c, fn.typ, entry[])
   n.sons[genericParamsPos] = ast.emptyNode
-  # semantic checking for the parameters:
-  if n.sons[paramsPos].kind != nkEmpty:
-    removeDefaultParamValues(n.sons[ParamsPos])
-    semParamList(c, n.sons[ParamsPos], nil, result)
-  else:
-    result.typ = newTypeS(tyProc, c)
-    rawAddSon(result.typ, nil)
-  result.typ.callConv = fn.typ.callConv
-  if result.kind == skIterator: result.typ.flags.incl(tfIterator)
   var oldPrc = GenericCacheGet(fn, entry[])
   if oldPrc == nil:
     fn.procInstCache.safeAdd(entry)
@@ -179,15 +269,9 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   popInfoContext()
   closeScope(c)           # close scope for parameters
   popOwner()
+  #c.currentScope = oldScope
   c.friendModule = oldFriend
   dec(c.InstCounter)
   if result.kind == skMethod: finishMethod(c, result)
-  
-proc instGenericContainer(c: PContext, n: PNode, header: PType): PType = 
-  var cl: TReplTypeVars
-  InitIdTable(cl.symMap)
-  InitIdTable(cl.typeMap)
-  cl.info = n.info
-  cl.c = c
-  result = ReplaceTypeVarsT(cl, header)
+
 
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 4de1f9151..33c0adac1 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -721,7 +721,8 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
       #   TGObj[T] = object
       #   TAlias[T] = TGObj[T]
       # 
-      a.sons[1] = semGenericParamList(c, a.sons[1], s.typ)
+      s.typ.n = semGenericParamList(c, a.sons[1], s.typ)
+      a.sons[1] = s.typ.n
       s.typ.size = -1 # could not be computed properly
       # we fill it out later. For magic generics like 'seq', it won't be filled
       # so we use tyEmpty instead of nil to not crash for strange conversions
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 4d465ead7..8ae23f851 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -226,7 +226,7 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
   else:
     LocalError(n.info, errXExpectsOneTypeParam, "ordinal")
     result = newOrPrevType(tyError, prev, c)
-  
+
 proc semTypeIdent(c: PContext, n: PNode): PSym =
   if n.kind == nkSym: 
     result = n.sym
@@ -236,16 +236,18 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
       markUsed(n, result)
       if result.kind == skParam and result.typ.kind == tyTypeDesc:
         # This is a typedesc param. is it already bound?
-        # it's not bound when it's also used as return type for example
-        if result.typ.sonsLen > 0:
+        # it's not bound when it's used multiple times in the
+        # proc signature for example
+        if c.InGenericInst > 0:
           let bound = result.typ.sons[0].sym
-          if bound != nil:
-            return bound
+          if bound != nil: return bound
           return result
         if result.typ.sym == nil:
           LocalError(n.info, errTypeExpected)
           return errorSym(c, n)
-        return result.typ.sym
+        result = result.typ.sym.copySym
+        result.typ = copyType(result.typ, result.typ.owner, true)
+        result.typ.flags.incl tfUnresolved
       if result.kind != skType: 
         # this implements the wanted ``var v: V, x: V`` feature ...
         var ov: TOverloadIter
@@ -382,7 +384,7 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
       # for ``{}`` we want to trigger the type mismatch in ``fitNode``:
       if r.kind != nkCurly or len(r) == 0:
         checkMinSonsLen(t, 1)
-        branch.sons[i] = fitNode(c, t.sons[0].typ, r)
+        branch.sons[i] = skipConv(fitNode(c, t.sons[0].typ, r))
         inc(covered)
       else:
         # constant sets have special rules
@@ -585,81 +587,95 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
   else:
     if sfGenSym notin param.flags: addDecl(c, param)
 
-proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind):
-  tuple[typ: PType, id: PIdent] =
-  # if typ is not-nil, the param should be turned into a generic param
-  # if id is not nil, the generic param will bind just once (see below)
+proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
+                   paramType: PType, paramName: string,
+                   info: TLineInfo, anon = false): PType =
+  if procKind in {skMacro, skTemplate}:
+    # generic param types in macros and templates affect overload
+    # resolution, but don't work as generic params when it comes
+    # to proc instantiation. We don't need to lift such params here.  
+    return
+
+  proc addImplicitGenericImpl(typeClass: PType, typId: PIdent): PType =
+    let finalTypId = if typId != nil: typId
+                     else: getIdent(paramName & ":type")
+    # is this a bindOnce type class already present in the param list?
+    for i in countup(0, genericParams.len - 1):
+      if genericParams.sons[i].sym.name.id == finalTypId.id:
+        return genericParams.sons[i].typ
+
+    var s = newSym(skType, finalTypId, getCurrOwner(), info)
+    if typId == nil: s.flags.incl(sfAnon)
+    s.linkTo(typeClass)
+    s.position = genericParams.len
+    genericParams.addSon(newSymNode(s))
+    result = typeClass
+
+  # XXX: There are codegen errors if this is turned into a nested proc
+  template liftingWalk(typ: PType, anonFlag = false): expr =
+    liftParamType(c, procKind, genericParams, typ, paramName, info, anonFlag)
+  #proc liftingWalk(paramType: PType, anon = false): PType =
+
+  var paramTypId = if not anon and paramType.sym != nil: paramType.sym.name
+                   else: nil
+
+  template addImplicitGeneric(e: expr): expr =
+    addImplicitGenericImpl(e, paramTypId)
+
   case paramType.kind:
   of tyExpr:
     if paramType.sonsLen == 0:
       # proc(a, b: expr)
       # no constraints, treat like generic param
-      result.typ = newTypeS(tyGenericParam, c)
+      result = addImplicitGeneric(newTypeS(tyGenericParam, c))
     else:
       # proc(a: expr{string}, b: expr{nkLambda})
       # overload on compile time values and AST trees
-      result.typ = newTypeS(tyExpr, c)
-      result.typ.sons = paramType.sons
+      result = addImplicitGeneric(c.newTypeWithSons(tyExpr, paramType.sons))
   of tyTypeDesc:
-    if tfInstantiated notin paramType.flags:
-      result.typ = newTypeS(tyTypeDesc, c)
-      result.typ.sons = paramType.sons
+    if tfUnresolved notin paramType.flags:
+      result = addImplicitGeneric(c.newTypeWithSons(tyTypeDesc, paramType.sons))
   of tyDistinct:
-    result = paramTypeClass(c, paramType.lastSon, procKind)
-    # disable the bindOnce behavior for the type class
-    result.id = nil
-    return
+    if paramType.sonsLen == 1:
+      # disable the bindOnce behavior for the type class
+      result = liftingWalk(paramType.sons[0], true)
+  of tySequence, tySet, tyArray, tyOpenArray:
+    # XXX: this is a bit strange, but proc(s: seq)
+    # produces tySequence(tyGenericParam, null).
+    # This also seems to be true when creating aliases
+    # like: type myseq = distinct seq.
+    # Maybe there is another better place to associate
+    # the seq type class with the seq identifier.
+    if paramType.lastSon == nil:
+      let typ = c.newTypeWithSons(tyTypeClass, @[newTypeS(paramType.kind, c)])
+      result = addImplicitGeneric(typ)
+    else:
+      for i in 0 .. <paramType.sons.len:
+        var lifted = liftingWalk(paramType.sons[i])
+        if lifted != nil:
+          paramType.sons[i] = lifted
+          result = paramType
   of tyGenericBody:
     # type Foo[T] = object
     # proc x(a: Foo, b: Foo) 
-    result.typ = newTypeS(tyTypeClass, c)
-    result.typ.addSonSkipIntLit(paramType)
+    var typ = newTypeS(tyTypeClass, c)
+    typ.addSonSkipIntLit(paramType)
+    result = addImplicitGeneric(typ)
+  of tyGenericInst:
+    for i in 1 .. (paramType.sons.len - 2):
+      var lifted = liftingWalk(paramType.sons[i])
+      if lifted != nil:
+        paramType.sons[i] = lifted
+        result = paramType
+    
+    if result != nil:
+      result.kind = tyGenericInvokation
+      result.sons.setLen(result.sons.len - 1)
   of tyTypeClass:
-    result.typ = copyType(paramType, getCurrOwner(), false)
+    result = addImplicitGeneric(copyType(paramType, getCurrOwner(), false))
   else: nil
-  # bindOnce by default
-  if paramType.sym != nil: result.id = paramType.sym.name
-
-proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
-                   paramType: PType, paramName: string,
-                   info: TLineInfo): PType =
-  result = paramType
-  if procKind in {skMacro, skTemplate}:
-    # generic param types in macros and templates affect overload
-    # resolution, but don't work as generic params when it comes
-    # to proc instantiation. We don't need to lift such params here.  
-    return
-  ## Params having implicit generic types or pseudo types such as 'expr'
-  ## need to be added to the generic params lists. 
-  ## 'expr' is different from 'expr{string}' so we must first call 
-  ## paramTypeClass to get the actual type we are going to use.
-  var (typeClass, paramTypId) = paramTypeClass(c, paramType, procKind)
-  let isAnon = paramTypId == nil
-  if typeClass != nil:
-    if isAnon: paramTypId = getIdent(paramName & ":type")
-    if genericParams == nil:
-      # genericParams is nil when the proc is being instantiated
-      # the resolved type will be in scope then
-      let s = searchInScopes(c, paramTypId)
-      # tests/run/tinterf triggers this:
-      if s != nil: result = s.typ
-      else:
-        LocalError(info, errCannotInstantiateX, paramName)
-        result = errorType(c)
-    else:
-      block addImplicitGeneric:
-        # is this a bindOnce type class already present in the param list?
-        for i in countup(0, genericParams.len - 1):
-          if genericParams.sons[i].sym.name.id == paramTypId.id:
-            result = genericParams.sons[i].typ
-            break addImplicitGeneric
 
-        var s = newSym(skType, paramTypId, getCurrOwner(), info)
-        if isAnon: s.flags.incl(sfAnon)
-        s.linkTo(typeClass)
-        s.position = genericParams.len
-        genericParams.addSon(newSymNode(s))
-        result = typeClass
+  # result = liftingWalk(paramType)
 
 proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType =
   if n.kind == nkCurlyExpr:
@@ -698,10 +714,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       length = sonsLen(a)
       hasType = a.sons[length-2].kind != nkEmpty
       hasDefault = a.sons[length-1].kind != nkEmpty
-
     if hasType:
       typ = semParamType(c, a.sons[length-2], constraint)
-      
+
     if hasDefault:
       def = semExprWithType(c, a.sons[length-1]) 
       # check type compability between def.typ and typ:
@@ -719,8 +734,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
     if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
     for j in countup(0, length-3): 
       var arg = newSymG(skParam, a.sons[j], c)
-      var finalType = liftParamType(c, kind, genericParams, typ, arg.name.s, 
-                                    a.sons[length-2].info).skipIntLit
+      let lifted = liftParamType(c, kind, genericParams, typ,
+                                 arg.name.s, arg.info)
+      let finalType = if lifted != nil: lifted else: typ.skipIntLit
       arg.typ = finalType
       arg.position = counter
       arg.constraint = constraint
@@ -738,11 +754,13 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
     # compiler only checks for 'nil':
     if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
       if r.sym == nil or sfAnon notin r.sym.flags:
-        r = liftParamType(c, kind, genericParams, r, "result", n.sons[0].info)
+        let lifted = liftParamType(c, kind, genericParams, r, "result",
+                                   n.sons[0].info)
+        if lifted != nil: r = lifted
         r.flags.incl tfRetType
       result.sons[0] = skipIntLit(r)
       res.typ = result.sons[0]
-
+ 
 proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
   checkMinSonsLen(n, 1)
   var length = sonsLen(n)
@@ -788,29 +806,47 @@ proc semGenericParamInInvokation(c: PContext, n: PNode): PType =
 
 proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = 
   result = newOrPrevType(tyGenericInvokation, prev, c)
-  var isConcrete = true
+  addSonSkipIntLit(result, s.typ)
+  
+  template addToResult(typ) =
+    if typ.isNil:
+      InternalAssert false
+      rawAddSon(result, typ)
+    else: addSonSkipIntLit(result, typ)
+
   if s.typ == nil:
     LocalError(n.info, errCannotInstantiateX, s.name.s)
     return newOrPrevType(tyError, prev, c)
-  elif s.typ.kind != tyGenericBody:
-    isConcrete = false
-  elif sonsLen(n) != sonsLen(s.typ): 
-    LocalError(n.info, errWrongNumberOfArguments)
-    return newOrPrevType(tyError, prev, c)
-  addSonSkipIntLit(result, s.typ)
-  # iterate over arguments:
-  for i in countup(1, sonsLen(n)-1):
-    var elem = semGenericParamInInvokation(c, n.sons[i])
-    if containsGenericType(elem): isConcrete = false
-    #if elem.kind in {tyGenericParam, tyGenericInvokation}: isConcrete = false
-    if elem.isNil: rawAddSon(result, elem)
-    else: addSonSkipIntLit(result, elem)
-  if isConcrete:
-    if s.ast == nil: 
-      LocalError(n.info, errCannotInstantiateX, s.name.s)
-      result = newOrPrevType(tyError, prev, c)
-    else:
-      result = instGenericContainer(c, n, result)
+  elif s.typ.kind == tyForward:
+    for i in countup(1, sonsLen(n)-1):
+      var elem = semGenericParamInInvokation(c, n.sons[i])
+      addToResult(elem)
+  else:
+    internalAssert s.typ.kind == tyGenericBody
+
+    var m = newCandidate(s, n)
+    matches(c, n, copyTree(n), m)
+    
+    if m.state != csMatch:
+      var err = "cannot instantiate " & typeToString(s.typ) & "\n" &
+                "got: (" & describeArgs(c, n) & ")\n" &
+                "but expected: (" & describeArgs(c, s.typ.n, 0) & ")"
+      LocalError(n.info, errGenerated, err)
+      return newOrPrevType(tyError, prev, c)
+
+    var isConcrete = true
+  
+    for i in 1 .. <m.call.len:
+      let typ = m.call[i].typ.skipTypes({tyTypeDesc})
+      if containsGenericType(typ): isConcrete = false
+      addToResult(typ)
+    
+    if isConcrete:
+      if s.ast == nil:
+        LocalError(n.info, errCannotInstantiateX, s.name.s)
+        result = newOrPrevType(tyError, prev, c)
+      else:
+        result = instGenericContainer(c, n, result)
 
 proc semTypeExpr(c: PContext, n: PNode): PType =
   var n = semExprWithType(c, n, {efDetermineType})
@@ -1014,55 +1050,61 @@ proc processMagicType(c: PContext, m: PSym) =
   of mPNimrodNode: nil
   else: LocalError(m.info, errTypeExpected)
   
-proc semGenericConstraints(c: PContext, n: PNode, result: PType) = 
-  var x = semTypeNode(c, n, nil)
+proc semGenericConstraints(c: PContext, x: PType): PType =
   if x.kind in StructuralEquivTypes and (
       sonsLen(x) == 0 or x.sons[0].kind in {tyGenericParam, tyEmpty}):
-    x = newConstraint(c, x.kind)
-  result.addSonSkipIntLit(x)
+    result = newConstraint(c, x.kind)
+  else:
+    result = newTypeWithSons(c, tyGenericParam, @[x])
 
 proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = 
   result = copyNode(n)
   if n.kind != nkGenericParams: 
     illFormedAst(n)
     return
-  for i in countup(0, sonsLen(n)-1): 
+  for i in countup(0, sonsLen(n)-1):
     var a = n.sons[i]
     if a.kind != nkIdentDefs: illFormedAst(n)
-    var L = sonsLen(a)
-    var def = a.sons[L-1]
+    let L = a.len
+    var def = a{-1}
+    let constraint = a{-2}
     var typ: PType
-    if a.sons[L-2].kind != nkEmpty: 
-      typ = newTypeS(tyGenericParam, c)
-      semGenericConstraints(c, a.sons[L-2], typ)
-      if sonsLen(typ) == 1 and typ.sons[0].kind == tyTypeDesc:
-        typ = typ.sons[0]
-    elif def.kind != nkEmpty: typ = newTypeS(tyExpr, c)
-    else: typ = nil
-    for j in countup(0, L-3): 
-      var s: PSym
+    
+    if constraint.kind != nkEmpty:
+      typ = semTypeNode(c, constraint, nil)
+      if typ.kind != tyExpr or typ.len == 0:
+        if typ.len == 0 and typ.kind == tyTypeDesc:
+          typ = newTypeS(tyGenericParam, c)
+        else:
+          typ = semGenericConstraints(c, typ)
+    
+    if def.kind != nkEmpty:
+      def = semConstExpr(c, def)
       if typ == nil:
-        s = newSymG(skType, a.sons[j], c)
-        s.typ = newTypeS(tyGenericParam, c)
+        if def.typ.kind != tyTypeDesc:
+          typ = newTypeWithSons(c, tyExpr, @[def.typ])
       else:
-        case typ.kind
-        of tyTypeDesc: 
-          s = newSymG(skType, a.sons[j], c)
-          s.typ = newTypeS(tyGenericParam, c)
+        if not containsGenericType(def.typ):
+          def = fitNode(c, typ, def)
+    
+    if typ == nil:
+      typ = newTypeS(tyGenericParam, c)
+    
+    for j in countup(0, L-3):
+      let finalType = if j == 0: typ
+                      else: copyType(typ, typ.owner, false)
+                      # it's important the we create an unique
+                      # type for each generic param. the index
+                      # of the parameter will be stored in the
+                      # attached symbol.
+      var s = case finalType.kind
         of tyExpr:
-          #echo "GENERIC EXPR ", a.info.toFileLineCol
-          # not a type param, but an expression
-          # proc foo[x: expr](bar: int) what is this?
-          s = newSymG(skGenericParam, a.sons[j], c)
-          s.typ = typ
+          newSymG(skGenericParam, a.sons[j], c).linkTo(finalType)
         else:
-          # This handles cases like proc foo[t: tuple] 
-          # XXX: we want to turn that into a type class
-          s = newSymG(skType, a.sons[j], c)
-          s.typ = typ
+          newSymG(skType, a.sons[j], c).linkTo(finalType)
       if def.kind != nkEmpty: s.ast = def
-      s.typ.sym = s
       if father != nil: addSonSkipIntLit(father, s.typ)
-      s.position = i
+      s.position = result.len
       addSon(result, newSymNode(s))
       if sfGenSym notin s.flags: addDecl(c, s)
+
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index a3e108a34..626d16d64 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -38,6 +38,7 @@ type
     proxyMatch*: bool        # to prevent instantiations
     genericConverter*: bool  # true if a generic converter needs to
                              # be instantiated
+    typedescMatched: bool
     inheritancePenalty: int  # to prefer closest father object type
   
   TTypeRelation* = enum      # order is important!
@@ -89,6 +90,9 @@ proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode,
       #debug(formalTypeParam)
       put(c.bindings, formalTypeParam, binding[i].typ)
 
+proc newCandidate*(callee: PSym, binding: PNode, calleeScope = -1): TCandidate =
+  initCandidate(result, callee, binding, calleeScope)
+
 proc copyCandidate(a: var TCandidate, b: TCandidate) = 
   a.exactMatches = b.exactMatches
   a.subtypeMatches = b.subtypeMatches
@@ -177,15 +181,9 @@ proc argTypeToString(arg: PNode): string =
   else:
     result = arg.typ.typeToString
 
-proc NotFoundError*(c: PContext, n: PNode) =
-  # Gives a detailed error message; this is separated from semOverloadedCall,
-  # as semOverlodedCall is already pretty slow (and we need this information
-  # only in case of an error).
-  if c.InCompilesContext > 0: 
-    # fail fast:
-    GlobalError(n.info, errTypeMismatch, "")
-  var result = msgKindToString(errTypeMismatch)
-  for i in countup(1, sonsLen(n) - 1):
+proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string =
+  result = ""
+  for i in countup(startIdx, n.len - 1):
     var arg = n.sons[i]
     if n.sons[i].kind == nkExprEqExpr: 
       add(result, renderTree(n.sons[i].sons[0]))
@@ -201,6 +199,16 @@ proc NotFoundError*(c: PContext, n: PNode) =
     if arg.typ.kind == tyError: return
     add(result, argTypeToString(arg))
     if i != sonsLen(n) - 1: add(result, ", ")
+
+proc NotFoundError*(c: PContext, n: PNode) =
+  # Gives a detailed error message; this is separated from semOverloadedCall,
+  # as semOverlodedCall is already pretty slow (and we need this information
+  # only in case of an error).
+  if c.InCompilesContext > 0: 
+    # fail fast:
+    GlobalError(n.info, errTypeMismatch, "")
+  var result = msgKindToString(errTypeMismatch)
+  add(result, describeArgs(c, n))
   add(result, ')')
   var candidates = ""
   var o: TOverloadIter
@@ -492,8 +500,11 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   of tyOrdinal:
     if isOrdinalType(a):
       var x = if a.kind == tyOrdinal: a.sons[0] else: a
+      
       result = typeRel(c, f.sons[0], x)
       if result < isGeneric: result = isNone
+    elif a.kind == tyGenericParam:
+      result = isGeneric
   of tyForward: InternalError("forward type in typeRel()")
   of tyNil:
     if a.kind == f.kind: result = isEqual
@@ -611,7 +622,24 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   of tyGenericParam, tyTypeClass:
     var x = PType(idTableGet(c.bindings, f))
     if x == nil:
-      result = matchTypeClass(c, f, a)
+      if c.calleeSym.kind == skType and f.kind == tyGenericParam and not c.typedescMatched:
+        # XXX: The fact that generic types currently use tyGenericParam for 
+        # their parameters is really a misnomer. tyGenericParam means "match
+        # any value" and what we need is "match any type", which can be encoded
+        # by a tyTypeDesc params. Unfortunately, this requires more substantial
+        # changes in semtypinst and elsewhere.
+        if a.kind == tyTypeDesc:
+          if f.sons == nil or f.sons.len == 0:
+            result = isGeneric
+          else:
+            InternalAssert a.sons != nil and a.sons.len > 0
+            c.typedescMatched = true
+            result = typeRel(c, f.sons[0], a.sons[0])
+        else:
+          result = isNone
+      else:
+        result = matchTypeClass(c, f, a)
+        
       if result == isGeneric:
         var concrete = concreteType(c, a)
         if concrete == nil:
@@ -909,16 +937,22 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
       else:
         m.state = csNoMatch
         return
-  
-  var f = 1 # iterates over formal parameters
-  var a = 1 # iterates over the actual given arguments
-  m.state = csMatch           # until proven otherwise
+
+  var
+    # iterates over formal parameters
+    f = if m.callee.kind != tyGenericBody: 1
+        else: 0
+    # iterates over the actual given arguments
+    a = 1
+
+  m.state = csMatch # until proven otherwise
   m.call = newNodeI(n.kind, n.info)
   m.call.typ = base(m.callee) # may be nil
-  var formalLen = sonsLen(m.callee.n)
+  var formalLen = m.callee.n.len
   addSon(m.call, copyTree(n.sons[0]))
   var container: PNode = nil # constructed container
   var formal: PSym = nil
+
   while a < n.len:
     if n.sons[a].kind == nkExprEqExpr:
       # named param
diff --git a/compiler/types.nim b/compiler/types.nim
index 6c4249b83..2564741d8 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -926,11 +926,21 @@ proc commonSuperclass*(a, b: PType): PType =
     if ancestors.contains(y.id): return y
     y = y.sons[0]
 
-proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool
-proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool = 
+type
+  TTypeAllowedFlag = enum
+    taField,
+    taHeap
+
+  TTypeAllowedFlags = set[TTypeAllowedFlag]
+
+proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind,
+                    flags: TTypeAllowedFlags = {}): bool
+
+proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind,
+                     flags: TTypeAllowedFlags = {}): bool =
   result = true
   if n != nil: 
-    result = typeAllowedAux(marker, n.typ, kind)
+    result = typeAllowedAux(marker, n.typ, kind, flags)
     #if not result: debug(n.typ)
     if result: 
       case n.kind
@@ -938,7 +948,7 @@ proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool =
         nil
       else: 
         for i in countup(0, sonsLen(n) - 1): 
-          result = typeAllowedNode(marker, n.sons[i], kind)
+          result = typeAllowedNode(marker, n.sons[i], kind, flags)
           if not result: break
 
 proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
@@ -959,8 +969,8 @@ proc skipGenericAlias*(t: PType): PType =
 proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
   for i in countup(0, typeClass.sonsLen - 1):
     let req = typeClass.sons[i]
-    var match = req.kind == skipTypes(t, {tyGenericInst, tyRange}).kind or
-                req.kind == skipTypes(t, {tyGenericInst}).kind
+    var match = req.kind == skipTypes(t, {tyRange, tyGenericInst}).kind
+
     if not match:
       case req.kind
       of tyGenericBody:
@@ -969,7 +979,9 @@ proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
           IdTablePut(bindings, typeClass, t)
       of tyTypeClass:
         match = matchTypeClass(bindings, req, t)
-      else: nil
+      elif t.kind == tyTypeClass:
+        match = matchTypeClass(bindings, t, req)
+          
     elif t.kind in {tyObject} and req.len != 0:
       # empty 'object' is fine as constraint in a type class
       match = sameType(t, req)
@@ -982,13 +994,16 @@ proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
   # if the loop finished without returning, either all constraints matched
   # or none of them matched.
   result = if tfAny in typeClass.flags: false else: true
+  if result == true:
+    IdTablePut(bindings, typeClass, t)
 
 proc matchTypeClass*(typeClass, typ: PType): bool =
   var bindings: TIdTable
   initIdTable(bindings)
   result = matchTypeClass(bindings, typeClass, typ)
 
-proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
+proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind,
+                    flags: TTypeAllowedFlags = {}): bool =
   assert(kind in {skVar, skLet, skConst, skParam, skResult})
   # if we have already checked the type, return true, because we stop the
   # evaluation if something is wrong:
@@ -1002,66 +1017,70 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
     var t2 = skipTypes(t.sons[0], abstractInst-{tyTypeDesc})
     case t2.kind
     of tyVar: 
-      result = false          # ``var var`` is always an invalid type:
+      result = taHeap in flags # ``var var`` is illegal on the heap:
     of tyOpenArray: 
-      result = kind == skParam and typeAllowedAux(marker, t2, kind)
+      result = kind == skParam and typeAllowedAux(marker, t2, kind, flags)
     else:
-      result = kind in {skParam, skResult} and typeAllowedAux(marker, t2, kind)
+      result = kind in {skParam, skResult} and
+               typeAllowedAux(marker, t2, kind, flags)
   of tyProc: 
     for i in countup(1, sonsLen(t) - 1): 
-      result = typeAllowedAux(marker, t.sons[i], skParam)
+      result = typeAllowedAux(marker, t.sons[i], skParam, flags)
       if not result: break 
     if result and t.sons[0] != nil:
-      result = typeAllowedAux(marker, t.sons[0], skResult)
+      result = typeAllowedAux(marker, t.sons[0], skResult, flags)
   of tyExpr, tyStmt, tyTypeDesc:
     result = true
     # XXX er ... no? these should not be allowed!
+  of tyEmpty:
+    result = taField in flags
   of tyTypeClass:
     result = true
   of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation:
     result = false
-  of tyEmpty, tyNil:
+  of tyNil:
     result = kind == skConst
   of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer: 
     result = true
   of tyOrdinal: 
     result = kind == skParam
   of tyGenericInst, tyDistinct: 
-    result = typeAllowedAux(marker, lastSon(t), kind)
-  of tyRange:
+    result = typeAllowedAux(marker, lastSon(t), kind, flags)
+  of tyRange: 
     result = skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind in
-        {tyChar, tyEnum, tyInt..tyUInt64}
+        {tyChar, tyEnum, tyInt..tyFloat128}
   of tyOpenArray, tyVarargs: 
-    result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar)
+    result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar, flags)
   of tySequence: 
     result = t.sons[0].kind == tyEmpty or 
-        typeAllowedAux(marker, t.sons[0], skVar)
+        typeAllowedAux(marker, t.sons[0], skVar, flags+{taHeap})
   of tyArray:
     result = t.sons[1].kind == tyEmpty or
-        typeAllowedAux(marker, t.sons[1], skVar)
+        typeAllowedAux(marker, t.sons[1], skVar, flags)
   of tyRef:
     if kind == skConst: return false
-    result = typeAllowedAux(marker, t.sons[0], skVar)
+    result = typeAllowedAux(marker, t.sons[0], skVar, flags+{taHeap})
   of tyPtr:
-    result = typeAllowedAux(marker, t.sons[0], skVar)
-  of tyArrayConstr, tyTuple, tySet, tyConst, tyMutable, tyIter:
+    result = typeAllowedAux(marker, t.sons[0], skVar, flags+{taHeap})
+  of tyArrayConstr, tySet, tyConst, tyMutable, tyIter:
     for i in countup(0, sonsLen(t) - 1):
-      result = typeAllowedAux(marker, t.sons[i], kind)
+      result = typeAllowedAux(marker, t.sons[i], kind, flags)
       if not result: break
-  of tyObject:
-    if kind == skConst: return false
+  of tyObject, tyTuple:
+    if kind == skConst and t.kind == tyObject: return false
+    let flags = flags+{taField}
     for i in countup(0, sonsLen(t) - 1): 
-      result = typeAllowedAux(marker, t.sons[i], kind)
+      result = typeAllowedAux(marker, t.sons[i], kind, flags)
       if not result: break
-    if result and t.n != nil: result = typeAllowedNode(marker, t.n, kind)
+    if result and t.n != nil: result = typeAllowedNode(marker, t.n, kind, flags)
   of tyProxy:
     # for now same as error node; we say it's a valid type as it should
     # prevent cascading errors:
     result = true
-    
+
 proc typeAllowed(t: PType, kind: TSymKind): bool = 
   var marker = InitIntSet()
-  result = typeAllowedAux(marker, t, kind)
+  result = typeAllowedAux(marker, t, kind, {})
 
 proc align(address, alignment: biggestInt): biggestInt = 
   result = (address + (alignment - 1)) and not (alignment - 1)