summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2012-10-03 20:51:22 +0200
committerAraq <rumpf_a@web.de>2012-10-03 20:51:22 +0200
commitc2b8669e04560e486e5df21b1217e6b9684ba88e (patch)
treecdff4a9c1ba92e7feb1990989caff5415fe83dd5 /compiler
parent9fbee85cc9dd95c1f99e5b55a3d382196eabb7fc (diff)
parent34e62d9f734189a9237725569aa282e9bedc11a3 (diff)
downloadNim-c2b8669e04560e486e5df21b1217e6b9684ba88e.tar.gz
Merge branch 'master' of github.com:Araq/Nimrod
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/ast.nim7
-rwxr-xr-xcompiler/evals.nim35
-rwxr-xr-xcompiler/msgs.nim17
-rwxr-xr-xcompiler/parser.nim8
-rwxr-xr-xcompiler/sem.nim11
-rwxr-xr-xcompiler/semexprs.nim138
-rwxr-xr-xcompiler/semfold.nim11
-rwxr-xr-xcompiler/semgnrc.nim23
-rwxr-xr-xcompiler/seminst.nim11
-rwxr-xr-xcompiler/semtypes.nim52
-rwxr-xr-xcompiler/semtypinst.nim3
-rwxr-xr-xcompiler/sigmatch.nim32
-rwxr-xr-xcompiler/types.nim37
13 files changed, 266 insertions, 119 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 814784029..aa94644aa 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -350,6 +350,8 @@ type
                       # pass of semProcTypeNode performed after instantiation.
                       # this won't be needed if we don't perform this redundant
                       # second pass (stay tuned).
+    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)
     tfAny,            # type class requires any constraint to be met
     tfCapturesEnv,    # whether proc really captures some environment
@@ -779,6 +781,11 @@ proc add*(father, son: PNode) =
 proc `[]`*(n: PNode, i: int): PNode {.inline.} =
   result = n.sons[i]
 
+# son access operators with support for negative indices
+template `{}`*(n: PNode, i: int): expr = n[i -| n]
+template `{}=`*(n: PNode, i: int, s: PNode): stmt =
+  n.sons[i -| n] = s
+  
 var emptyNode* = newNode(nkEmpty)
 # There is a single empty node that is shared! Do not overwrite it!
 
diff --git a/compiler/evals.nim b/compiler/evals.nim
index 9c73a6b78..226415815 100755
--- a/compiler/evals.nim
+++ b/compiler/evals.nim
@@ -41,6 +41,7 @@ type
     callsite: PNode           # for 'callsite' magic
     mode*: TEvalMode
     globals*: TIdNodeTable    # state of global vars
+    getType*: proc(n: PNode): PNode
   
   PEvalContext* = ref TEvalContext
 
@@ -521,7 +522,7 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
   else: result = nil
   if result == nil or {sfImportc, sfForward} * s.flags != {}:
     result = raiseCannotEval(c, n.info)
-  
+
 proc evalIncDec(c: PEvalContext, n: PNode, sign: biggestInt): PNode = 
   result = evalAux(c, n.sons[1], {efLValue})
   if isSpecial(result): return 
@@ -875,6 +876,27 @@ proc evalTypeTrait*(n: PNode, context: PSym): PNode =
   else:
     internalAssert false
 
+proc evalIsOp*(n: PNode): PNode =
+  InternalAssert n.sonsLen == 3 and
+    n[1].kind == nkSym and n[1].sym.kind == skType and
+    n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
+  
+  let t1 = n[1].sym.typ
+
+  if n[2].kind in {nkStrLit..nkTripleStrLit}:
+    case n[2].strVal.normalize
+    of "closure":
+      let t = skipTypes(t1, abstractRange)
+      result = newIntNode(nkIntLit, ord(t.kind == tyProc and
+                                        t.callConv == ccClosure))
+  else:
+    let t2 = n[2].typ
+    var match = if t2.kind == tyTypeClass: matchTypeClass(t2, t1)
+                else: sameType(t1, t2)
+    result = newIntNode(nkIntLit, ord(match))
+
+  result.typ = n.typ
+
 proc expectString(n: PNode) =
   if n.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
     GlobalError(n.info, errStringLiteralExpected)
@@ -968,6 +990,9 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
   of mTypeTrait:
     n.sons[1] = evalAux(c, n.sons[1], {})
     result = evalTypeTrait(n, c.module)
+  of mIs:
+    n.sons[1] = evalAux(c, n.sons[1], {})
+    result = evalIsOp(n)
   of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module)
   of mStaticExec:
     let cmd = evalAux(c, n.sons[1], {})
@@ -1067,7 +1092,10 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
     result = evalAux(c, n.sons[1], {})
     if isSpecial(result): return 
     if result.kind != nkIdent: stackTrace(c, n, errFieldXNotFound, "ident")
-  of mNGetType: result = evalAux(c, n.sons[1], {})
+  of mNGetType:
+    var ast = evalAux(c, n.sons[1], {})
+    InternalAssert c.getType != nil
+    result = c.getType(ast)
   of mNStrVal: 
     result = evalAux(c, n.sons[1], {})
     if isSpecial(result): return 
@@ -1128,7 +1156,8 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
     var a = result
     result = evalAux(c, n.sons[2], {efLValue})
     if isSpecial(result): return 
-    a.typ = result.typ        # XXX: exception handling?
+    InternalAssert result.kind == nkSym and result.sym.kind == skType
+    a.typ = result.sym.typ
     result = emptyNode
   of mNSetStrVal:
     result = evalAux(c, n.sons[1], {efLValue})
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 0ad79f597..c793c1c68 100755
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -575,19 +575,22 @@ proc inCheckpoint*(current: TLineInfo): TCheckPointResult =
 type
   TErrorHandling = enum doNothing, doAbort, doRaise
 
-proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) = 
-  if msg == errInternal: 
-    assert(false)             # we want a stack trace here
+proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
+  template maybeTrace =
+    if defined(debug) or gVerbosity >= 3:
+      writeStackTrace()
+
+  if msg == errInternal:
+    writeStackTrace() # we always want a stack trace here
   if msg >= fatalMin and msg <= fatalMax: 
-    if gVerbosity >= 3: assert(false)
+    maybeTrace()
     quit(1)
   if msg >= errMin and msg <= errMax: 
-    if gVerbosity >= 3: assert(false)
+    maybeTrace()
     inc(gErrorCounter)
     options.gExitcode = 1'i8
     if gErrorCounter >= gErrorMax or eh == doAbort: 
-      if gVerbosity >= 3: assert(false)
-      quit(1)                 # one error stops the compiler
+      quit(1)                        # one error stops the compiler
     elif eh == doRaise:
       raiseRecoverableError(s)
   
diff --git a/compiler/parser.nim b/compiler/parser.nim
index cdbe42c7e..7612980c5 100755
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -743,7 +743,7 @@ proc isExprStart(p: TParser): bool =
   case p.tok.tokType
   of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkProc, tkBind, 
      tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr, 
-     tkTuple, tkType, tkWhen:
+     tkTuple, tkType, tkWhen, tkCase:
     result = true
   else: result = false
   
@@ -763,9 +763,9 @@ proc parseExpr(p: var TParser): PNode =
   case p.tok.tokType:
   of tkIf: result = parseIfExpr(p, nkIfExpr)
   of tkWhen: result = parseIfExpr(p, nkWhenExpr)
+  of tkCase: result = parseCase(p)
   else: result = lowestExpr(p)
   # XXX needs proper support:
-  #of tkCase: result = parseCase(p)
   #of tkTry: result = parseTry(p)
 
 proc primary(p: var TParser, skipSuffix = false): PNode = 
@@ -1044,9 +1044,9 @@ proc parseCase(p: var TParser): PNode =
     if b.kind == nkElse: break
   
   if wasIndented:
-    eat(p, tkDed)
+    if p.tok.tokType != tkEof: eat(p, tkDed)
     popInd(p.lex)
-
+    
 proc parseTry(p: var TParser): PNode = 
   result = newNodeP(nkTryStmt, p)
   getTok(p)
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 397581f63..0a6159dfa 100755
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -43,6 +43,7 @@ proc addParams(c: PContext, n: PNode, kind: TSymKind)
 proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind)
 proc addResultNode(c: PContext, n: PNode)
 proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
+proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
 
 proc typeMismatch(n: PNode, formal, actual: PType) = 
   if formal.kind != tyError and actual.kind != tyError: 
@@ -156,8 +157,18 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
   markUsed(n, sym)
   if sym == c.p.owner:
     GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
+
   if c.evalContext == nil:
     c.evalContext = newEvalContext(c.module, "", emStatic)
+    c.evalContext.getType = proc (n: PNode): PNode =
+      var e = tryExpr(c, n)
+      if e == nil:
+        result = symNodeFromType(c, errorType(c), n.info)
+      elif e.typ == nil:
+        result = newSymNode(getSysSym"void")
+      else:
+        result = symNodeFromType(c, e.typ, n.info)
+
   result = evalMacroCall(c.evalContext, n, nOrig, sym)
   if semCheck: result = semAfterMacroCall(c, result, sym)
 
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 7c147e778..e9dc5a8e9 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -281,18 +281,29 @@ proc semOf(c: PContext, n: PNode): PNode =
   n.typ = getSysType(tyBool)
   result = n
 
-proc semIs(c: PContext, n: PNode): PNode = 
-  if sonsLen(n) == 3:
-    n.typ = getSysType(tyBool)
-    let a = semTypeNode(c, n[1], nil)
-    n.sons[1] = newNodeIT(nkType, n[1].info, a)
-    if n[2].kind notin {nkStrLit..nkTripleStrLit}:
-      let b = semTypeNode(c, n[2], nil)
-      n.sons[2] = newNodeIT(nkType, n[2].info, b)
-  else:
+proc semIs(c: PContext, n: PNode): PNode =
+  if sonsLen(n) != 3:
     LocalError(n.info, errXExpectsTwoArguments, "is")
+
   result = n
+  n.typ = getSysType(tyBool)
+  
+  n.sons[1] = semExprWithType(c, n[1])
+  if n[1].typ.kind != tyTypeDesc:
+    LocalError(n[0].info, errTypeExpected)
+
+  if n[2].kind notin {nkStrLit..nkTripleStrLit}:
+    let t2 = semTypeNode(c, n[2], nil)
+    n.sons[2] = newNodeIT(nkType, n[2].info, t2)
 
+  if n[1].typ.sonsLen == 0:
+    # this is a typedesc variable, leave for evals
+    return
+  else:
+    let t1 = n[1].typ.sons[0]
+    # BUGFIX: don't evaluate this too early: ``T is void``
+    if not containsGenericType(t1): result = evalIsOp(n)
+  
 proc semOpAux(c: PContext, n: PNode, tailToExclude = 1) =
   for i in countup(1, sonsLen(n) - tailToExclude):
     var a = n.sons[i]
@@ -1048,8 +1059,20 @@ proc semAsgn(c: PContext, n: PNode): PNode =
     localError(a.info, errXCannotBeAssignedTo, 
                renderTree(a, {renderNoComments}))
   else:
-    n.sons[1] = semExprWithType(c, n.sons[1])
-    n.sons[1] = fitNode(c, le, n.sons[1])
+    var 
+      rhs = semExprWithType(c, n.sons[1])
+      lhs = n.sons[0]
+    if lhs.kind == nkSym and lhs.sym.kind == skResult and
+       lhs.sym.typ.kind == tyGenericParam:
+      if matchTypeClass(lhs.typ, rhs.typ):
+        InternalAssert c.p.resultSym != nil
+        lhs.typ = rhs.typ
+        c.p.resultSym.typ = rhs.typ
+        c.p.owner.typ.sons[0] = rhs.typ
+      else:
+        typeMismatch(n, lhs.typ, rhs.typ)
+
+    n.sons[1] = fitNode(c, le, rhs)
     fixAbstractType(c, n)
     asgnToResultVar(c, n, n.sons[0], n.sons[1])
   result = n
@@ -1214,12 +1237,7 @@ proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
   else:
     result = semDirectOp(c, n, flags)
 
-proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
-  # we replace this node by a 'true' or 'false' node:
-  if sonsLen(n) != 2: return semDirectOp(c, n, flags)
-  result = newIntNode(nkIntLit, 0)
-  result.info = n.info
-  result.typ = getSysType(tyBool)
+proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   # watch out, hacks ahead:
   let oldErrorCount = msgs.gErrorCounter
   let oldErrorMax = msgs.gErrorMax
@@ -1241,8 +1259,8 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
   let oldProcCon = c.p
   c.generics = newGenericsCache()
   try:
-    discard semExpr(c, n.sons[1])
-    result.intVal = ord(msgs.gErrorCounter == oldErrorCount)
+    result = semExpr(c, n, flags)
+    if msgs.gErrorCounter != oldErrorCount: result = nil
   except ERecoverableError:
     nil
   # undo symbol table changes (as far as it's possible):
@@ -1259,6 +1277,14 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
   msgs.gErrorCounter = oldErrorCount
   msgs.gErrorMax = oldErrorMax
 
+proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  # we replace this node by a 'true' or 'false' node:
+  if sonsLen(n) != 2: return semDirectOp(c, n, flags)
+  
+  result = newIntNode(nkIntLit, ord(tryExpr(c, n, flags) != nil))
+  result.info = n.info
+  result.typ = getSysType(tyBool)
+
 proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
   if sonsLen(n) == 3:
     # XXX ugh this is really a hack: shallowCopy() can be overloaded only
@@ -1352,19 +1378,28 @@ proc semSetConstr(c: PContext, n: PNode): PNode =
         m = fitNode(c, typ, n.sons[i])
       addSon(result, m)
 
-proc semTableConstr(c: PContext, n: PNode): PNode = 
-  # we simply transform ``{key: value, key2: value}`` to 
-  # ``[(key, value), (key2, value2)]``
+proc semTableConstr(c: PContext, n: PNode): PNode =
+  # we simply transform ``{key: value, key2, key3: value}`` to 
+  # ``[(key, value), (key2, value2), (key3, value2)]``
   result = newNodeI(nkBracket, n.info)
+  var lastKey = 0
   for i in 0..n.len-1:
     var x = n.sons[i]
     if x.kind == nkExprColonExpr and sonsLen(x) == 2:
+      for j in countup(lastKey, i-1):
+        var pair = newNodeI(nkPar, x.info)
+        pair.add(n.sons[j])
+        pair.add(x[1])
+        result.add(pair)
+
       var pair = newNodeI(nkPar, x.info)
       pair.add(x[0])
       pair.add(x[1])
       result.add(pair)
-    else:
-      illFormedAst(x)
+
+      lastKey = i+1
+
+  if lastKey != n.len: illFormedAst(n)
   result = semExpr(c, result)
 
 type 
@@ -1507,6 +1542,57 @@ proc semMacroStmt(c: PContext, n: PNode, flags: TExprFlags,
                renderTree(a, {renderNoComments}))
     result = errorNode(c, n)
 
+proc semCaseExpr(c: PContext, caseStmt: PNode): PNode =
+  # The case expression is simply rewritten to a StmtListExpr:
+  #   var res {.noInit, genSym.}: type(values)
+  #
+  #   case E
+  #   of X: res = value1
+  #   of Y: res = value2
+  # 
+  #   res
+  var
+    info = caseStmt.info
+    resVar = newSym(skVar, getIdent":res", getCurrOwner(), info)
+    resNode = newSymNode(resVar, info)
+    resType: PType
+
+  resVar.flags = { sfGenSym, sfNoInit }
+
+  for i in countup(1, caseStmt.len - 1):
+    var cs = caseStmt[i]
+    case cs.kind
+    of nkOfBranch, nkElifBranch, nkElse:
+      # the value is always the last son regardless of the branch kind
+      cs.checkMinSonsLen 1
+      var value = cs{-1}
+      if value.kind == nkStmtList: value.kind = nkStmtListExpr
+
+      value = semExprWithType(c, value)
+      if resType == nil:
+        resType = value.typ
+      elif not sameType(resType, value.typ):
+        # XXX: semeType is a bit too harsh.
+        # work on finding a common base type.
+        # this will be useful for arrays/seq too:
+        # [ref DerivedA, ref DerivedB, ref Base]
+        typeMismatch(cs, resType, value.typ)
+
+      cs{-1} = newNode(nkAsgn, cs.info, @[resNode, value])
+    else:
+      IllFormedAst(caseStmt)
+
+  result = newNode(nkStmtListExpr, info, @[
+    newNode(nkVarSection, info, @[
+      newNode(nkIdentDefs, info, @[
+        resNode,
+        symNodeFromType(c, resType, info),
+        emptyNode])]),
+    caseStmt,
+    resNode])
+
+  result = semStmtListExpr(c, result)
+    
 proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = 
   result = n
   if gCmd == cmdIdeTools: suggestExpr(c, n)
@@ -1686,7 +1772,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkTryStmt: result = semTry(c, n)
   of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n)
   of nkForStmt, nkParForStmt: result = semFor(c, n)
-  of nkCaseStmt: result = semCase(c, n)
+  of nkCaseStmt:
+    if efWantStmt in flags: result = semCase(c, n)
+    else: result = semCaseExpr(c, n)
   of nkReturnStmt: result = semReturn(c, n)
   of nkAsmStmt: result = semAsm(c, n)
   of nkYieldStmt: result = semYield(c, n)
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index c2958ca5e..d0805d921 100755
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -610,17 +610,6 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
           result = newIntNodeT(sonsLen(a), n)
         else:
           result = magicCall(m, n)
-      of mIs:
-        # BUGFIX: don't evaluate this too early: ``T is void``
-        if not containsGenericType(n[1].typ):
-          if n[2].kind in {nkStrLit..nkTripleStrLit}:
-            case n[2].strVal.normalize
-            of "closure":
-              let t = skipTypes(n[1].typ, abstractRange)
-              result = newIntNodeT(ord(t.kind == tyProc and
-                                       t.callConv == ccClosure), n)
-          elif not containsGenericType(n[2].typ):
-            result = newIntNodeT(ord(sameType(n[1].typ, n[2].typ)), n)
       of mAstToStr:
         result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
       of mConStrStr:
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index 2751aa1e1..bffa8ad8e 100755
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -261,16 +261,16 @@ proc semGenericStmt(c: PContext, n: PNode,
       else: 
         a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, toBind)
   of nkEnumTy: 
-    checkMinSonsLen(n, 1)
-    if n.sons[0].kind != nkEmpty: 
-      n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, toBind)
-    for i in countup(1, sonsLen(n) - 1): 
-      var a: PNode
-      case n.sons[i].kind
-      of nkEnumFieldDef: a = n.sons[i].sons[0]
-      of nkIdent: a = n.sons[i]
-      else: illFormedAst(n)
-      addDeclAt(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c), c.tab.tos-1)
+    if n.sonsLen > 0:
+      if n.sons[0].kind != nkEmpty: 
+        n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, toBind)
+      for i in countup(1, sonsLen(n) - 1): 
+        var a: PNode
+        case n.sons[i].kind
+        of nkEnumFieldDef: a = n.sons[i].sons[0]
+        of nkIdent: a = n.sons[i]
+        else: illFormedAst(n)
+        addDeclAt(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c), c.tab.tos-1)
   of nkObjectTy, nkTupleTy: 
     nil
   of nkFormalParams: 
@@ -306,6 +306,9 @@ proc semGenericStmt(c: PContext, n: PNode,
     n.sons[bodyPos] = semGenericStmtScope(c, body, flags, toBind)
     closeScope(c.tab)
   of nkPragma, nkPragmaExpr: nil
+  of nkExprColonExpr:
+    checkMinSonsLen(n, 2)
+    result.sons[1] = semGenericStmt(c, n.sons[1], flags, toBind)
   else: 
     for i in countup(0, sonsLen(n) - 1): 
       result.sons[i] = semGenericStmt(c, n.sons[i], flags, toBind)
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 61210c0f8..8e164531a 100755
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -25,8 +25,13 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
     s.flags = s.flags + {sfUsed, sfFromGeneric}
     var t = PType(IdTableGet(pt, q.typ))
     if t == nil:
-      LocalError(a.info, errCannotInstantiateX, s.name.s)
-      t = errorType(c)
+      if tfRetType in q.typ.flags:
+        # keep the generic type and allow the return type to be bound 
+        # later by semAsgn in return type inference scenario
+        t = q.typ
+      else:
+        LocalError(a.info, errCannotInstantiateX, s.name.s)
+        t = errorType(c)
     elif t.kind == tyGenericParam: 
       InternalError(a.info, "instantiateGenericParamList: " & q.name.s)
     elif t.kind == tyGenericInvokation:
@@ -163,7 +168,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
     result.typ = newTypeS(tyProc, c)
     rawAddSon(result.typ, nil)
   result.typ.callConv = fn.typ.callConv
-  ParamsTypeCheck(c, result.typ)
   var oldPrc = GenericCacheGet(c, entry)
   if oldPrc == nil:
     c.generics.generics.add(entry)
@@ -174,6 +178,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
     if fn.kind != skTemplate:
       instantiateBody(c, n, result)
       sideEffectsCheck(c, result)
+    ParamsTypeCheck(c, result.typ)
   else:
     result = oldPrc
   popInfoContext()
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 5362d6d4a..c41727b10 100755
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -584,22 +584,20 @@ proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind):
       result.typ = newTypeS(tyTypeDesc, c)
       result.typ.sons = paramType.sons
   of tyDistinct:
-    # type T1 = distinct expr
-    # type S1 = distinct Sortable
-    # proc x(a, b: T1, c, d: S1)
-    # This forces bindOnce behavior for the type class, equivalent to
-    # proc x[T, S](a, b: T, c, d: S)
     result = paramTypeClass(c, paramType.lastSon, procKind)
-    result.id = paramType.sym.name
+    # disable the bindOnce behavior for the type class
+    result.id = nil
+    return
   of tyGenericBody:
     # type Foo[T] = object
     # proc x(a: Foo, b: Foo) 
     result.typ = newTypeS(tyTypeClass, c)
     result.typ.addSonSkipIntLit(paramType)
-    result.id = paramType.sym.name # bindOnce by default
   of tyTypeClass:
     result.typ = 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,
@@ -619,7 +617,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
       let s = SymtabGet(c.tab, paramTypId)
       # tests/run/tinterf triggers this:
       if s != nil: result = s.typ
-      else: 
+      else:
         LocalError(info, errCannotInstantiateX, paramName)
         result = errorType(c)
     else:
@@ -684,8 +682,8 @@ 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,
-                                    arg.info).skipIntLit
+      var finalType = liftParamType(c, kind, genericParams, typ,
+                                    arg.name.s, arg.info).skipIntLit
       arg.typ = finalType
       arg.position = counter
       inc(counter)
@@ -703,6 +701,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
     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)
+        r.flags.incl tfRetType
       result.sons[0] = skipIntLit(r)
       res.typ = result.sons[0]
 
@@ -800,22 +799,25 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
       LocalError(n.info, errTypeExpected)
       result = newOrPrevType(tyError, prev, c)
   of nkCallKinds:
-    let op = n.sons[0].ident
-    if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
-      var
-        t1 = semTypeNode(c, n.sons[1], nil)
-        t2 = semTypeNode(c, n.sons[2], nil)
-      if   t1 == nil: 
-        LocalError(n.sons[1].info, errTypeExpected)
-        result = newOrPrevType(tyError, prev, c)
-      elif t2 == nil: 
-        LocalError(n.sons[2].info, errTypeExpected)
-        result = newOrPrevType(tyError, prev, c)
+    if n[0].kind == nkIdent:
+      let op = n.sons[0].ident
+      if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
+        var
+          t1 = semTypeNode(c, n.sons[1], nil)
+          t2 = semTypeNode(c, n.sons[2], nil)
+        if   t1 == nil: 
+          LocalError(n.sons[1].info, errTypeExpected)
+          result = newOrPrevType(tyError, prev, c)
+        elif t2 == nil: 
+          LocalError(n.sons[2].info, errTypeExpected)
+          result = newOrPrevType(tyError, prev, c)
+        else:
+          result = newTypeS(tyTypeClass, c)
+          result.addSonSkipIntLit(t1)
+          result.addSonSkipIntLit(t2)
+          result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny)
       else:
-        result = newTypeS(tyTypeClass, c)
-        result.addSonSkipIntLit(t1)
-        result.addSonSkipIntLit(t2)
-        result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny)
+        result = semTypeExpr(c, n)
     else:
       result = semTypeExpr(c, n)
   of nkCurlyExpr:
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index d75594dff..70453c6db 100755
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -59,6 +59,7 @@ type
 
 proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType
 proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
+proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode
 
 proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
   result = copyNode(n)
@@ -66,7 +67,7 @@ proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
   for i in 0 .. safeLen(n)-1: 
     # XXX HACK: ``f(a, b)``, avoid to instantiate `f` 
     if i == 0: result.add(n[i])
-    else: result.add(prepareNode(cl, n[i]))
+    else: result.add(ReplaceTypeVarsN(cl, n[i]))
 
 proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
   if n == nil: return
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 7e482b3d2..8f1ca5f36 100755
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -11,7 +11,7 @@
 ## the call to overloaded procs, generic procs and operators.
 
 import 
-  intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, 
+  intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
   magicsys, condsyms, idents, lexer, options
 
 type
@@ -257,32 +257,6 @@ proc tupleRel(c: var TCandidate, f, a: PType): TTypeRelation =
           var y = a.n.sons[i].sym
           if x.name.id != y.name.id: return isNone
 
-proc matchTypeClass(c: var TCandidate, typeClass, t: PType): TTypeRelation =
-  for i in countup(0, typeClass.sonsLen - 1):
-    let req = typeClass.sons[i]
-    var match = req.kind == skipTypes(t, {tyRange, tyGenericInst}).kind
-      
-    if not match:
-      case req.kind
-      of tyGenericBody:
-        if t.kind == tyGenericInst and t.sons[0] == req:
-          match = true
-          put(c.bindings, typeClass, t)
-      of tyTypeClass:
-        match = matchTypeClass(c, req, t) == isGeneric
-      else: nil
-    elif t.kind in {tyObject}:
-      match = sameType(t, req)
-
-    if tfAny in typeClass.flags:
-      if match: return isGeneric
-    else:
-      if not match: return isNone
-
-  # if the loop finished without returning, either all constraints matched
-  # or none of them matched.
-  result = if tfAny in typeClass.flags: isNone else: isGeneric
-  
 proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
     result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
@@ -325,6 +299,10 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
         result = isNone
   else: nil
 
+proc matchTypeClass(c: var TCandidate, f, a: PType): TTypeRelation =
+  result = if matchTypeClass(c.bindings, f, a): isGeneric
+           else: isNone
+
 proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation = 
   # is a subtype of f?
   result = isNone
diff --git a/compiler/types.nim b/compiler/types.nim
index d8879f1b4..e02d93233 100755
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -626,9 +626,9 @@ proc SameTypeOrNil*(a, b: PType, flags: TTypeCmpFlags = {}): bool =
       var c = initSameTypeClosure()
       c.flags = flags
       result = SameTypeAux(a, b, c)
-  
+
 proc equalParam(a, b: PSym): TParamsEquality = 
-  if SameTypeOrNil(a.typ, b.typ): 
+  if SameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}): 
     if a.ast == b.ast: 
       result = paramsEqual
     elif a.ast != nil and b.ast != nil: 
@@ -904,7 +904,38 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
     if i >= a.sonslen or a.sons[i] == nil: return false
     a = a.sons[i]
   result = a.kind == last
-  
+
+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, {tyRange, tyGenericInst}).kind
+      
+    if not match:
+      case req.kind
+      of tyGenericBody:
+        if t.kind == tyGenericInst and t.sons[0] == req:
+          match = true
+          IdTablePut(bindings, typeClass, t)
+      of tyTypeClass:
+        match = matchTypeClass(bindings, req, t)
+      else: nil
+    elif t.kind in {tyObject}:
+      match = sameType(t, req)
+
+    if tfAny in typeClass.flags:
+      if match: return true
+    else:
+      if not match: return false
+
+  # if the loop finished without returning, either all constraints matched
+  # or none of them matched.
+  result = if tfAny in typeClass.flags: false else: true
+
+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 =
   assert(kind in {skVar, skLet, skConst, skParam, skResult})
   # if we have already checked the type, return true, because we stop the