summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/ast.nim14
-rw-r--r--compiler/ccgcalls.nim1
-rwxr-xr-xcompiler/ccgtypes.nim8
-rwxr-xr-xcompiler/ccgutils.nim4
-rwxr-xr-xcompiler/cgen.nim1
-rwxr-xr-xcompiler/ecmasgen.nim2
-rwxr-xr-xcompiler/evals.nim15
-rw-r--r--compiler/idgen.nim7
-rwxr-xr-xcompiler/lookups.nim7
-rwxr-xr-xcompiler/msgs.nim5
-rwxr-xr-xcompiler/options.nim3
-rwxr-xr-xcompiler/sem.nim2
-rwxr-xr-xcompiler/semdata.nim10
-rwxr-xr-xcompiler/semexprs.nim44
-rwxr-xr-xcompiler/seminst.nim4
-rwxr-xr-xcompiler/semtempl.nim61
-rwxr-xr-xcompiler/semtypes.nim151
-rwxr-xr-xcompiler/semtypinst.nim1
-rwxr-xr-xcompiler/sigmatch.nim83
-rwxr-xr-xcompiler/transf.nim2
-rwxr-xr-xcompiler/types.nim19
21 files changed, 271 insertions, 173 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 7fd92d8fc..897501ee5 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -258,7 +258,7 @@ type
     tyGenericParam,      # ``a`` in the above patterns
     tyDistinct,
     tyEnum,
-    tyOrdinal,           # misnamed: should become 'tyConstraint'
+    tyOrdinal,           # integer types (including enums and boolean)
     tyArray,
     tyObject,
     tyTuple,
@@ -277,6 +277,7 @@ type
     tyConst, tyMutable, tyVarargs, 
     tyIter, # unused
     tyProxy # currently unused
+    tyTypeClass,
 
 const
   tyPureObject* = tyTuple
@@ -308,6 +309,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
+    tfAll             # type class requires all constraints to be met (default)
+    tfAny             # type class requires any constraint to be met
 
   TTypeFlags* = set[TTypeFlag]
 
@@ -707,6 +710,15 @@ proc `[]`*(n: PNode, i: int): PNode {.inline.} =
 var emptyNode* = newNode(nkEmpty)
 # There is a single empty node that is shared! Do not overwrite it!
 
+proc linkTo*(t: PType, s: PSym): PType {.discardable.} =
+  t.sym = s
+  s.typ = t
+  result = t
+
+proc linkTo*(s: PSym, t: PType): PSym {.discardable.} =
+  t.sym = s
+  s.typ = t
+  result = s
 
 const                         # for all kind of hash tables:
   GrowthFactor* = 2           # must be power of 2, > 0
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 072b2f9fb..cb6014626 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -130,6 +130,7 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
   var length = sonsLen(ri)
   for i in countup(1, length - 1):
     assert(sonsLen(typ) == sonsLen(typ.n))
+    if ri.sons[i].typ.isCompileTimeOnly: continue
     if i < sonsLen(typ):
       assert(typ.n.sons[i].kind == nkSym)
       app(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym))
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 8c211186f..6195ff2f4 100755
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -7,6 +7,8 @@
 #    distribution, for details about the copyright.
 #
 
+# included from cgen.nim
+
 # ------------------------- Name Mangling --------------------------------
 
 proc mangle(name: string): string = 
@@ -48,6 +50,9 @@ proc mangleName(s: PSym): PRope =
     app(result, toRope(s.id))
     s.loc.r = result
 
+proc isCompileTimeOnly(t: PType): bool =
+  result = t.kind in {tyTypedesc, tyExpr}
+
 proc getTypeName(typ: PType): PRope = 
   if (typ.sym != nil) and ({sfImportc, sfExportc} * typ.sym.flags != {}) and
       (gCmd != cmdCompileToLLVM): 
@@ -187,6 +192,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
   for i in countup(1, sonsLen(t.n) - 1): 
     if t.n.sons[i].kind != nkSym: InternalError(t.n.info, "genProcParams")
     var param = t.n.sons[i].sym
+    if isCompileTimeOnly(param.typ): continue
     fillLoc(param.loc, locParam, param.typ, mangleName(param), OnStack)
     app(params, getParamTypeDesc(m, param.typ, check))
     if ccgIntroducedPtr(param): 
@@ -206,8 +212,8 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
       arr = arr.sons[0]
     if i < sonsLen(t.n) - 1: app(params, ", ")
   if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]): 
-    if params != nil: app(params, ", ")
     var arr = t.sons[0]
+    if params != nil: app(params, ", ")
     app(params, getTypeDescAux(m, arr, check))
     if (mapReturnType(t.sons[0]) != ctArray) or (gCmd == cmdCompileToLLVM): 
       app(params, "*")
diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim
index 610fcb39b..12795358a 100755
--- a/compiler/ccgutils.nim
+++ b/compiler/ccgutils.nim
@@ -82,9 +82,11 @@ proc GetUniqueType*(key: PType): PType =
     if result == nil:
       gCanonicalTypes[k] = key
       result = key
+  of tyGenericParam, tyTypeClass:
+    InternalError("GetUniqueType")
   of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter:
     result = GetUniqueType(lastSon(key))
-  of tyArrayConstr, tyGenericInvokation, tyGenericBody, tyGenericParam,
+  of tyArrayConstr, tyGenericInvokation, tyGenericBody,
      tyOpenArray, tyArray, tyTuple, tySet, tyRange, 
      tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar:
     # we have to do a slow linear search because types may need
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index d85d3fe53..a56053f79 100755
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -606,6 +606,7 @@ proc genProcAux(m: BModule, prc: PSym) =
         res.loc.s = OnUnknown
   for i in countup(1, sonsLen(prc.typ.n) - 1): 
     var param = prc.typ.n.sons[i].sym
+    if param.typ.isCompileTimeOnly: continue
     assignParam(p, param)
   closureSetup(p, prc)
   genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
diff --git a/compiler/ecmasgen.nim b/compiler/ecmasgen.nim
index 5307ea7d1..6499f7a6f 100755
--- a/compiler/ecmasgen.nim
+++ b/compiler/ecmasgen.nim
@@ -111,7 +111,7 @@ proc mapType(typ: PType): TEcmasTypeKind =
     result = etyObject
   of tyNil: result = etyNull
   of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation, tyNone, 
-     tyForward, tyEmpty, tyExpr, tyStmt, tyTypeDesc: 
+     tyForward, tyEmpty, tyExpr, tyStmt, tyTypeDesc, tyTypeClass: 
     result = etyNone
   of tyProc: result = etyProc
   of tyCString: result = etyString
diff --git a/compiler/evals.nim b/compiler/evals.nim
index 72c37a5d9..84d3023a5 100755
--- a/compiler/evals.nim
+++ b/compiler/evals.nim
@@ -16,7 +16,7 @@
 import 
   strutils, magicsys, lists, options, ast, astalgo, trees, treetab, nimsets, 
   msgs, os, condsyms, idents, renderer, types, passes, semfold, transf, 
-  parser, ropes, rodread
+  parser, ropes, rodread, idgen
 
 type 
   PStackFrame* = ref TStackFrame
@@ -843,6 +843,7 @@ proc evalParseStmt(c: PEvalContext, n: PNode): PNode =
   result.typ = newType(tyStmt, c.module)
 
 proc evalTemplateAux*(templ, actual: PNode, sym: PSym): PNode = 
+  inc genSymBaseId
   case templ.kind
   of nkSym: 
     var p = templ.sym
@@ -866,26 +867,29 @@ proc evalTemplateArgs(n: PNode, s: PSym): PNode =
   of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
     a = sonsLen(n)
   else: a = 0
-  var f = sonsLen(s.typ)  
+  var f = s.typ.sonsLen
   if a > f: GlobalError(n.info, errWrongNumberOfArguments)
 
   result = copyNode(n)
   for i in countup(1, f - 1):
     var arg = if i < a: n.sons[i] else: copyTree(s.typ.n.sons[i].sym.ast)
+    if arg == nil or arg.kind == nkEmpty:
+      LocalError(n.info, errWrongNumberOfArguments)
     addSon(result, arg)
 
-var evalTemplateCounter = 0
+var evalTemplateCounter* = 0
   # to prevent endless recursion in templates instantation
 
-proc evalTemplate(n: PNode, sym: PSym): PNode = 
+proc evalTemplate*(n: PNode, sym: PSym): PNode = 
   inc(evalTemplateCounter)
   if evalTemplateCounter > 100:
     GlobalError(n.info, errTemplateInstantiationTooNested)
+    result = n
 
   # replace each param by the corresponding node:
   var args = evalTemplateArgs(n, sym)
   result = evalTemplateAux(sym.getBody, args, sym)
-
+  
   dec(evalTemplateCounter)
   
 proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
@@ -1312,6 +1316,7 @@ proc evalMacroCall*(c: PEvalContext, n: PNode, sym: PSym): PNode =
   if evalTemplateCounter > 100: 
     GlobalError(n.info, errTemplateInstantiationTooNested)
 
+  inc genSymBaseId
   var s = newStackFrame()
   s.call = n
   setlen(s.params, 2)
diff --git a/compiler/idgen.nim b/compiler/idgen.nim
index 6dc19474d..d2e322796 100644
--- a/compiler/idgen.nim
+++ b/compiler/idgen.nim
@@ -11,7 +11,7 @@
 
 import idents, strutils, os, options
 
-var gFrontEndId, gBackendId*: int
+var gFrontEndId, gBackendId*, genSymBaseId*: int
 
 const
   debugIds* = false
@@ -25,7 +25,7 @@ proc registerID*(id: PIdObj) =
   when debugIDs: 
     if id.id == -1 or ContainsOrIncl(usedIds, id.id): 
       InternalError("ID already used: " & $id.id)
-  
+
 proc getID*(): int {.inline.} = 
   result = gFrontEndId
   inc(gFrontEndId)
@@ -34,6 +34,9 @@ proc backendId*(): int {.inline.} =
   result = gBackendId
   inc(gBackendId)
 
+proc genSym*(basename: string): PIdent =
+  result = getIdent(basename & $genSymBaseId)
+
 proc setId*(id: int) {.inline.} = 
   gFrontEndId = max(gFrontEndId, id + 1)
 
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index ee77b3633..62f4a3391 100755
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -11,7 +11,7 @@
 
 import 
   intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread, 
-  renderer
+  renderer, wordrecg, idgen
 
 proc considerAcc*(n: PNode): PIdent = 
   case n.kind
@@ -21,6 +21,11 @@ proc considerAcc*(n: PNode): PIdent =
     case n.len
     of 0: GlobalError(n.info, errIdentifierExpected, renderTree(n))
     of 1: result = considerAcc(n.sons[0])
+    of 2:
+      if n[0].ident.id == ord(wStar):
+        result = genSym(n[1].ident.s)
+      else:
+        result = getIdent(n[0].ident.s & n[1].ident.s)
     else:
       var id = ""
       for i in 0.. <n.len:
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index ef4a0a4cf..df9064ab2 100755
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -662,3 +662,8 @@ proc InternalError*(info: TLineInfo, errMsg: string) =
 proc InternalError*(errMsg: string) = 
   writeContext(UnknownLineInfo())
   rawMessage(errInternal, errMsg)
+
+template AssertNotNil*(e: expr): expr =
+  if(e == nil): InternalError($InstantiationInfo())
+  e
+
diff --git a/compiler/options.nim b/compiler/options.nim
index ff51ad66c..edea2288d 100755
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -219,3 +219,6 @@ proc binaryStrSearch*(x: openarray[string], y: string): int =
       return mid
   result = - 1
 
+# Can we keep this? I'm using it all the time
+template nimdbg*: expr = c.filename.endsWith"nimdbg.nim"
+  
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 7d296dbfc..e27f20503 100755
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -91,7 +91,7 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
 
 proc semAndEvalConstExpr(c: PContext, n: PNode): PNode = 
   result = semConstExpr(c, n)
-  
+
 include seminst, semcall
 
 proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode = 
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 49ab20290..80aed2fd4 100755
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -180,14 +180,16 @@ proc addToLib(lib: PLib, sym: PSym) =
   sym.annex = lib
 
 proc makePtrType(c: PContext, baseType: PType): PType = 
-  if (baseType == nil): InternalError("makePtrType")
   result = newTypeS(tyPtr, c)
-  addSon(result, baseType)
+  addSon(result, baseType.AssertNotNil)
 
 proc makeVarType(c: PContext, baseType: PType): PType = 
-  if (baseType == nil): InternalError("makeVarType")
   result = newTypeS(tyVar, c)
-  addSon(result, baseType)
+  addSon(result, baseType.AssertNotNil)
+
+proc makeTypeDesc*(c: PContext, typ: PType): PType =
+  result = newTypeS(tyTypeDesc, c)
+  result.addSon(typ.AssertNotNil)
 
 proc newTypeS(kind: TTypeKind, c: PContext): PType = 
   result = newType(kind, getCurrOwner())
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 147f38abb..0282c6c53 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -10,10 +10,12 @@
 # this module does the semantic checking for expressions
 # included from sem.nim
 
+proc semExprOrTypedesc(c: PContext, n: PNode): PNode
+
 proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode = 
   markUsed(n, s)
   pushInfoContext(n.info)
-  result = evalTemplate(c, n, s)
+  result = evalTemplate(n, s)
   if semCheck: result = semAfterMacroCall(c, result, s)
   popInfoContext()
 
@@ -93,6 +95,8 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
     # if a proc accesses a global variable, it is not side effect free:
     if sfGlobal in s.flags:
       incl(c.p.owner.flags, sfSideEffect)
+    elif s.kind == skParam and s.typ.kind == tyExpr:
+      return s.typ.n
     elif s.owner != c.p.owner and s.owner.kind != skModule and 
         c.p.owner.typ != nil and not IsGenericRoutine(s.owner):
       c.p.owner.typ.callConv = ccClosure
@@ -111,7 +115,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
   else:
     markUsed(n, s)
     result = newSymNode(s, n.info)
-
+  
 proc checkConversionBetweenObjects(info: TLineInfo, castDest, src: PType) =
   var diff = inheritanceDiff(castDest, src)
   if diff == high(int):
@@ -247,16 +251,31 @@ proc semIs(c: PContext, n: PNode): PNode =
   else:
     GlobalError(n.info, errXExpectsTwoArguments, "is")
 
+proc semExprOrTypedesc(c: PContext, n: PNode): PNode =
+  # XXX: Currently, semExprWithType will return the same type
+  # for nodes such as (100) or (int). 
+  # This is inappropriate. The type of the first expression
+  # should be "int", while the type of the second one should 
+  # be typeDesc(int).
+  # Ideally, this should be fixed in semExpr, but right now 
+  # there are probably users that depend on the present behavior.
+  # XXX: Investigate current uses of efAllowType and fix them to
+  # work with tyTypeDesc.
+  result = semExprWithType(c, n, {efAllowType})
+  if result.kind == nkSym and result.sym.kind == skType and
+     result.typ.kind != tyTypeDesc:
+    result.typ = makeTypeDesc(c, result.typ)
+
 proc semOpAux(c: PContext, n: PNode) =
   for i in countup(1, sonsLen(n) - 1):
     var a = n.sons[i]
     if a.kind == nkExprEqExpr and sonsLen(a) == 2: 
       var info = a.sons[0].info
       a.sons[0] = newIdentNode(considerAcc(a.sons[0]), info)
-      a.sons[1] = semExprWithType(c, a.sons[1], {efAllowType})
+      a.sons[1] = semExprOrTypedesc(c, a.sons[1])
       a.typ = a.sons[1].typ
     else:
-      n.sons[i] = semExprWithType(c, a, {efAllowType})
+      n.sons[i] = semExprOrTypedesc(c, a)
     
 proc overloadedCallOpr(c: PContext, n: PNode): PNode = 
   # quick check if there is *any* () operator overloaded:
@@ -822,7 +841,7 @@ proc semDeref(c: PContext, n: PNode): PNode =
   of tyRef, tyPtr: n.typ = t.sons[0]
   else: result = nil
   #GlobalError(n.sons[0].info, errCircumNeedsPointer) 
-  
+
 proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
   ## returns nil if not a built-in subscript operator; also called for the
   ## checking of assignments
@@ -833,7 +852,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
     result.add(x[0])
     return
   checkMinSonsLen(n, 2)
-  n.sons[0] = semExprWithType(c, n.sons[0], flags - {efAllowType})
+  n.sons[0] = semExprOrTypedesc(c, n.sons[0])
   var arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef})
   case arr.kind
   of tyArray, tyOpenArray, tyArrayConstr, tySequence, tyString, tyCString: 
@@ -848,6 +867,11 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
       result = n
       result.typ = elemType(arr)
     #GlobalError(n.info, errIndexTypesDoNotMatch)
+  of tyTypeDesc:
+    result = n.sons[0] # The result so far is a tyTypeDesc bound to
+                       # a tyGenericBody. The line below will substitute
+                       # it with the instantiated type.
+    result.typ.sons[0] = semTypeNode(c, n, nil).linkTo(result.sym)
   of tyTuple: 
     checkSonsLen(n, 2)
     n.sons[0] = makeDeref(n.sons[0])
@@ -1024,7 +1048,7 @@ proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
     markUsed(n, expandedSym)
 
     for i in countup(1, macroCall.len-1):
-      macroCall.sons[i] = semExprWithType(c, macroCall[i], {efAllowType})
+      macroCall.sons[i] = semExprWithType(c, macroCall[i], {})
 
     # Preserve the magic symbol in order to be handled in evals.nim
     n.sons[0] = newSymNode(magicSym, n.info)
@@ -1287,6 +1311,12 @@ 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:
+    var typ = semTypeNode(c, n, nil)
+    if typ.sym == nil:
+      typ = copyType(typ, typ.owner, true)
+      typ.linkTo(newSym(skType, getIdent"typedesc", typ.owner))
+    result = newSymNode(typ.sym, n.info)
   of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: 
     # check if it is an expression macro:
     checkMinSonsLen(n, 1)
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 9ec78488b..85c68923c 100755
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -20,7 +20,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
     if a.kind != nkSym: 
       InternalError(a.info, "instantiateGenericParamList; no symbol")
     var q = a.sym
-    if q.typ.kind notin {tyTypeDesc, tyGenericParam}: continue 
+    if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyTypeClass, tyExpr}: continue
     var s = newSym(skType, q.name, getCurrOwner())
     s.info = q.info
     s.flags = s.flags + {sfUsed, sfFromGeneric}
@@ -107,8 +107,6 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
       s.ast.sons[genericParamsPos].kind == nkEmpty:
     c.threadEntries.add(s)
 
-template nimdbg: expr = c.filename.endsWith"nimdbg.nim"
-
 proc applyConcreteTypesToSig(genericProc: PSym, concTypes: seq[PType]): PType =
   # XXX: This is intended to replace the use of semParamList in generateInstance.
   # The results of semParamList's analysis are already encoded in the original
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 2600d80cb..b0debc75b 100755
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -9,67 +9,6 @@
 
 # included from sem.nim
 
-proc isExpr(n: PNode): bool = 
-  # returns true if ``n`` looks like an expression
-  case n.kind
-  of nkIdent..nkNilLit: 
-    result = true
-  of nkCall..pred(nkAsgn): 
-    for i in countup(0, sonsLen(n) - 1): 
-      if not isExpr(n.sons[i]): 
-        return false
-    result = true
-  else: result = false
-  
-proc isTypeDesc(n: PNode): bool = 
-  # returns true if ``n`` looks like a type desc
-  case n.kind
-  of nkIdent, nkSym, nkType: 
-    result = true
-  of nkDotExpr, nkBracketExpr: 
-    for i in countup(0, sonsLen(n) - 1): 
-      if not isTypeDesc(n.sons[i]): 
-        return false
-    result = true
-  of nkTypeOfExpr..nkEnumTy: 
-    result = true
-  else: result = false
-  
-var evalTemplateCounter: int = 0
-  # to prevend endless recursion in templates instantation
-
-proc evalTemplateArgs(c: PContext, n: PNode, s: PSym): PNode = 
-  var 
-    f, a: int
-    arg: PNode
-  f = sonsLen(s.typ) 
-  # if the template has zero arguments, it can be called without ``()``
-  # `n` is then a nkSym or something similar
-  case n.kind
-  of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: 
-    a = sonsLen(n)
-  else: a = 0
-  if a > f: LocalError(n.info, errWrongNumberOfArguments)
-  result = copyNode(n)
-  for i in countup(1, f - 1): 
-    if i < a: arg = n.sons[i]
-    else: arg = copyTree(s.typ.n.sons[i].sym.ast)
-    if arg == nil or arg.kind == nkEmpty: 
-      LocalError(n.info, errWrongNumberOfArguments)
-    addSon(result, arg)
-
-proc evalTemplate*(c: PContext, n: PNode, sym: PSym): PNode = 
-  var args: PNode
-  inc(evalTemplateCounter)
-  if evalTemplateCounter <= 100: 
-    # replace each param by the corresponding node:
-    args = evalTemplateArgs(c, n, sym)
-    result = evalTemplateAux(sym.getBody, args, sym)
-    dec(evalTemplateCounter)
-  else:
-    GlobalError(n.info, errTemplateInstantiationTooNested)
-    result = n
-
 proc symChoice(c: PContext, n: PNode, s: PSym): PNode = 
   var 
     a: PSym
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index ee3595989..38cf19406 100755
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -180,6 +180,8 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
     result = qualifiedLookup(c, n, {checkAmbiguity, checkUndeclared})
     if result != nil:
       markUsed(n, result)
+      if result.kind == skParam and result.typ.kind == tyTypeDesc:
+        return result.typ.sons[0].sym
       if result.kind != skType: GlobalError(n.info, errTypeExpected)
       if result.typ.kind != tyGenericParam:
         # XXX get rid of this hack!
@@ -470,42 +472,6 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
   result.n = newNodeI(nkRecList, n.info)
   semRecordNodeAux(c, n.sons[2], check, pos, result.n, result.sym)
   
-proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode, 
-                              cl: var TIntSet): PType = 
-  result = t
-  if t == nil: return 
-  if ContainsOrIncl(cl, t.id): return 
-  case t.kind
-  of tyGenericBody: 
-    result = newTypeS(tyGenericInvokation, c)
-    addSon(result, t)
-    for i in countup(0, sonsLen(t) - 2): 
-      if t.sons[i].kind != tyGenericParam: 
-        InternalError("addTypeVarsOfGenericBody")
-      # do not declare ``TKey`` twice:
-      #if not ContainsOrIncl(cl, t.sons[i].sym.ident.id):
-      var s = copySym(t.sons[i].sym)
-      s.position = sonsLen(genericParams)
-      if s.typ == nil or s.typ.kind != tyGenericParam: 
-        InternalError("addTypeVarsOfGenericBody 2")
-      addDecl(c, s)
-      addSon(genericParams, newSymNode(s))
-      addSon(result, t.sons[i])
-  of tyGenericInst: 
-    var L = sonsLen(t) - 1
-    t.sons[L] = addTypeVarsOfGenericBody(c, t.sons[L], genericParams, cl)
-  of tyGenericInvokation: 
-    for i in countup(1, sonsLen(t) - 1): 
-      t.sons[i] = addTypeVarsOfGenericBody(c, t.sons[i], genericParams, cl)
-  else: 
-    for i in countup(0, sonsLen(t) - 1): 
-      t.sons[i] = addTypeVarsOfGenericBody(c, t.sons[i], genericParams, cl)
-  
-proc paramType(c: PContext, n, genericParams: PNode, cl: var TIntSet): PType = 
-  result = semTypeNode(c, n, nil)
-  if genericParams != nil and sonsLen(genericParams) == 0: 
-    result = addTypeVarsOfGenericBody(c, result, genericParams, cl)
-
 proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
   if kind == skMacro and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}:
     let nn = getSysSym"PNimrodNode"
@@ -515,8 +481,43 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
   else:
     addDecl(c, param)
 
-proc isTypeClass(c: PContext, t: PType): bool =
-  return t.kind in {tyExpr}
+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)
+  case paramType.kind:
+  of tyExpr:
+    if procKind notin {skTemplate, skMacro}:
+      if paramType.sonsLen == 0:
+        # proc(a, b: expr)
+        # no constraints, treat like generic param
+        result.typ = 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
+  of tyTypeDesc:
+    if procKind notin {skTemplate, skMacro}:
+      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
+  of tyGenericBody:
+    # type Foo[T] = object
+    # proc x(a: Foo, b: Foo) 
+    result.typ = newTypeS(tyTypeClass, c)
+    result.typ.addSon(paramType)
+    result.id = paramType.sym.name # bindOnce by default
+  of tyTypeClass:
+    result.typ = copyType(paramType, getCurrOwner(), false)
+  else: nil
 
 proc semProcTypeNode(c: PContext, n, genericParams: PNode, 
                      prev: PType, kind: TSymKind): PType = 
@@ -546,9 +547,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       hasDefault = a.sons[length-1].kind != nkEmpty
 
     if hasType:
-      typ = paramType(c, a.sons[length-2], genericParams, cl)
-      #if matchType(typ, [(tyVar, 0)], tyGenericInvokation):
-      #  debug a.sons[length-2][0][1]
+      typ = semTypeNode(c, a.sons[length-2], nil)
+      
     if hasDefault:
       def = semExprWithType(c, a.sons[length-1]) 
       # check type compability between def.typ and typ:
@@ -566,40 +566,46 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
     if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
     for j in countup(0, length-3): 
       var arg = newSymS(skParam, a.sons[j], c)
-      arg.typ = typ
-      if kind notin {skTemplate, skMacro} and isTypeClass(c, typ):
-        let typeClassParamId = getIdent(":tcls_" & $i & "_" & $j)
+      var endingType = typ
+      var (typeClass, paramTypId) = paramTypeClass(c, typ, kind)
+      if typeClass != nil:
+        if paramTypId == nil: paramTypId = getIdent(arg.name.s & ":type")
         if genericParams == nil:
           # genericParams is nil when the proc is being instantiated
           # the resolved type will be in scope then
-          var s = SymtabGet(c.tab, typeClassParamId)
-          arg.typ = s.typ
+          endingType = SymtabGet(c.tab, paramTypId).AssertNotNil.typ
         else:
-          var s = newSym(skType, typeClassParamId, getCurrOwner())
-          s.typ = newTypeS(tyGenericParam, c)
-          s.typ.sym = s
-          s.position = genericParams.len
-          genericParams.addSon(newSymNode(s))
-          arg.typ = s.typ
+          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 == paramTypId:
+                endingType = genericParams.sons[i].typ
+                break addImplicitGeneric
 
+            var s = newSym(skType, paramTypId, getCurrOwner())
+            s.typ = typeClass
+            s.typ.sym = s
+            s.position = genericParams.len
+            genericParams.addSon(newSymNode(s))
+            endingType = typeClass
+      
+      arg.typ = endingType
       arg.position = counter
       inc(counter)
       if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
       if ContainsOrIncl(check, arg.name.id): 
         LocalError(a.sons[j].info, errAttemptToRedefine, arg.name.s)
       addSon(result.n, newSymNode(arg))
-      addSon(result, typ)
+      addSon(result, endingType)
       addParamOrResult(c, arg, kind)
 
-  if n.sons[0].kind != nkEmpty: 
-    var r = paramType(c, n.sons[0], genericParams, cl)
+  if n.sons[0].kind != nkEmpty:
+    var r = semTypeNode(c, n.sons[0], nil)
     # turn explicit 'void' return type into 'nil' because the rest of the 
     # compiler only checks for 'nil':
     if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
       result.sons[0] = r
       res.typ = result.sons[0]
-  #if matchType(result, [(tyProc, 1), (tyVar, 0)], tyGenericInvokation):
-  #  debug result
 
 proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
   checkMinSonsLen(n, 1)
@@ -666,9 +672,10 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
     if s.ast == nil: GlobalError(n.info, errCannotInstantiateX, s.name.s)
     result = instGenericContainer(c, n, result)
 
-proc semExpandToType(c: PContext, n: PNode, sym: PSym): PType =
+proc semTypeFromMacro(c: PContext, n: PNode): PType =
   # Expands a macro or template until a type is returned
   # results in GlobalError if the macro expands to something different
+  var sym = expectMacroOrTemplateCall(c, n)
   markUsed(n, sym)
   case sym.kind
   of skMacro:
@@ -678,7 +685,7 @@ proc semExpandToType(c: PContext, n: PNode, sym: PSym): PType =
   else:
     GlobalError(n.info, errXisNoMacroOrTemplate, n.renderTree)
 
-proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = 
+proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   result = nil
   if gCmd == cmdIdeTools: suggestExpr(c, n)
   case n.kind
@@ -691,9 +698,27 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
     if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
     else: GlobalError(n.info, errTypeExpected)
   of nkCallKinds:
-    # expand macros and templates
-    var expandedSym = expectMacroOrTemplateCall(c, n)
-    result = semExpandToType(c, n, expandedSym)
+    let op = n.sons[0].ident.id
+    if op in {ord(wAnd), ord(wOr)}:
+      var
+        t1 = semTypeNode(c, n.sons[1], nil)
+        t2 = semTypeNode(c, n.sons[2], nil)
+
+      if   t1 == nil: GlobalError(n.sons[1].info, errTypeExpected)
+      elif t2 == nil: GlobalError(n.sons[2].info, errTypeExpected)
+      else:
+        result = newTypeS(tyTypeClass, c)
+        result.addSon(t1)
+        result.addSon(t2)
+        result.flags.incl(if op == ord(wAnd): tfAll else: tfAny)
+    else:
+      result = semTypeFromMacro(c, n)
+  of nkCurlyExpr:
+    result = semTypeNode(c, n.sons[0], nil)
+    if result != nil:
+      result = copyType(result, getCurrOwner(), false)
+      for i in countup(1, n.len - 1):
+        result.addSon(semTypeNode(c, n.sons[i], nil))
   of nkWhenStmt:
     var whenResult = semWhen(c, n, false)
     if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType
@@ -794,7 +819,7 @@ proc processMagicType(c: PContext, m: PSym) =
   else: GlobalError(m.info, errTypeExpected)
   
 proc newConstraint(c: PContext, k: TTypeKind): PType = 
-  result = newTypeS(tyOrdinal, c)
+  result = newTypeS(tyTypeClass, c)
   result.addSon(newTypeS(k, c))
   
 proc semGenericConstraints(c: PContext, n: PNode, result: PType) = 
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 903506a72..0c44205de 100755
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -202,6 +202,7 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
   result = t
   if t == nil: return 
   case t.kind
+  of tyTypeClass: nil
   of tyGenericParam:
     result = lookupTypeVar(cl, t)
     if result.kind == tyGenericInvokation:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 3db88569f..da804c2cb 100755
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -35,7 +35,7 @@ type
   
   TTypeRelation* = enum      # order is important!
     isNone, isConvertible, isIntConv, isSubtype, 
-    isGeneric, 
+    isGeneric
     isEqual
   
 proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} = 
@@ -208,10 +208,32 @@ proc tupleRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
         var y = a.n.sons[i].sym
         if x.name.id != y.name.id: return isNone
 
-proc constraintRel(mapping: var TIdTable, f, a: PType): TTypeRelation = 
-  result = isNone
-  if f.kind == a.kind: result = isGeneric
+proc matchTypeClass(mapping: var TIdTable, f, a: PType): TTypeRelation =
+  for i in countup(0, f.sonsLen - 1):
+    let son = f.sons[i]
+    var match = son.kind == a.kind
+
+    if not match:
+      case son.kind
+      of tyGenericBody:
+        if a.kind == tyGenericInst and a.sons[0] == son:
+          match = true
+          put(mapping, f, a)
+      of tyTypeClass:
+        match = matchTypeClass(mapping, son, a) == isGeneric
+      else: nil
 
+    if tfAny in f.flags:
+      if match == true:
+        return isGeneric
+    else:
+      if match == false:
+        return isNone
+
+  # if the loop finished without returning, either all constraints matched
+  # or none of them matched.
+  result = if tfAny in f.flags: isNone else: isGeneric
+  
 proc procTypeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
   proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
     result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
@@ -261,7 +283,8 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
   assert(a != nil)
   if a.kind == tyGenericInst and
       skipTypes(f, {tyVar}).kind notin {
-        tyGenericBody, tyGenericInvokation, tyGenericParam}:
+        tyGenericBody, tyGenericInvokation,
+        tyGenericParam, tyTypeClass }:
     return typeRel(mapping, f, lastSon(a))
   if a.kind == tyVar and f.kind != tyVar: 
     return typeRel(mapping, f, a.sons[0])
@@ -340,11 +363,8 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
         result = typeRel(mapping, f.sons[0], a.sons[0])
         if result < isGeneric: result = isNone
     else: nil
-  of tyOrdinal: 
-    if f.sons[0].kind != tyGenericParam: 
-      # some constraint:
-      result = constraintRel(mapping, f.sons[0], a)
-    elif isOrdinalType(a): 
+  of tyOrdinal:
+    if isOrdinalType(a):
       var x = if a.kind == tyOrdinal: a.sons[0] else: a
       result = typeRel(mapping, f.sons[0], x)
       if result < isGeneric: result = isNone
@@ -415,7 +435,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
   of tyGenericBody: 
     let ff = lastSon(f)
     if ff != nil: result = typeRel(mapping, ff, a)
-  of tyGenericInvokation: 
+  of tyGenericInvokation:
     assert(f.sons[0].kind == tyGenericBody)
     if a.kind == tyGenericInvokation: 
       #InternalError("typeRel: tyGenericInvokation -> tyGenericInvokation")
@@ -463,7 +483,19 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
       result = isGeneric
     else: 
       result = typeRel(mapping, x, a) # check if it fits
-  of tyExpr, tyStmt, tyTypeDesc:
+  of tyTypeClass:
+    result = matchTypeClass(mapping, f, a)
+    if result == isGeneric: put(mapping, f, a)
+  of tyTypeDesc:
+    if a.kind == tyTypeDesc:
+      if f.sonsLen == 0:
+        result = isGeneric
+      else:
+        result = matchTypeClass(mapping, f, a.sons[0])
+      if result == isGeneric: put(mapping, f, a)
+    else:
+      result = isNone
+  of tyExpr, tyStmt:
     result = isGeneric
   else: internalError("typeRel(" & $f.kind & ')')
   
@@ -506,9 +538,34 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
       inc(m.convMatches)
       return 
 
+
 proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType, 
                         arg, argOrig: PNode): PNode =
-  var r = typeRel(m.bindings, f, a)
+  var r: TTypeRelation
+  if f.kind == tyExpr:
+    if f.sonsLen == 0:
+      r = isGeneric
+    else:
+      let match = matchTypeClass(m.bindings, f, a)
+      if match != isGeneric: r = isNone
+      else:
+        # XXX: Ideally, this should happen much earlier somewhere near 
+        # semOpAux, but to do that, we need to be able to query the 
+        # overload set to determine whether compile-time value is expected
+        # for the param before entering the full-blown sigmatch algorithm.
+        # This is related to the immediate pragma since querying the
+        # overload set could help there too.
+        var evaluated = c.semConstExpr(c, arg)
+        if evaluated != nil:
+          r = isGeneric
+          arg.typ = newTypeS(tyExpr, c)
+          arg.typ.n = evaluated
+        
+    if r == isGeneric:
+      put(m.bindings, f, arg.typ)
+  else:
+    r = typeRel(m.bindings, f, a)
+  
   case r
   of isConvertible: 
     inc(m.convMatches)
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 0fa4883ea..ff42ff592 100755
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -429,7 +429,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
       result = generateThunk(c, x, dest).ptransnode
     else:
       result = transformSons(c, n)    
-  of tyGenericParam, tyOrdinal: 
+  of tyGenericParam, tyOrdinal, tyTypeClass:
     result = transform(c, n.sons[1])
     # happens sometimes for generated assignments, etc.
   else: 
diff --git a/compiler/types.nim b/compiler/types.nim
index efdc30dbf..3f7c2c820 100755
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -50,13 +50,13 @@ proc enumHasHoles*(t: PType): bool
 const 
   abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal,
                    tyConst, tyMutable}
-  abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal, 
+  abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal,
                   tyConst, tyMutable}
   abstractRange* = {tyGenericInst, tyRange, tyDistinct, tyOrdinal,
                     tyConst, tyMutable}
   abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
                        tyConst, tyMutable}
-  abstractInst* = {tyGenericInst, tyDistinct, tyOrdinal, tyConst, tyMutable}
+  abstractInst* = {tyGenericInst, tyDistinct, tyConst, tyMutable, tyOrdinal}
 
   skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable}
 
@@ -383,7 +383,7 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
       "int16", "int32", "int64", "float", "float32", "float64", "float128",
       
       "uint", "uint8", "uint16", "uint32", "uint64", "bignum", "const ",
-      "!", "varargs[$1]", "iter[$1]", "proxy[$1]"]
+      "!", "varargs[$1]", "iter[$1]", "proxy[$1]", "TypeClass" ]
   var t = typ
   result = ""
   if t == nil: return 
@@ -729,9 +729,11 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
       while a.kind == tyDistinct: a = a.sons[0]
       if a.kind != b.kind: return false
   case a.Kind
-  of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString, 
-     tyInt..tyBigNum, tyExpr, tyStmt, tyTypeDesc: 
+  of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
+     tyInt..tyBigNum, tyStmt:
     result = true
+  of tyExpr:
+    result = ExprStructuralEquivalent(a.n, b.n)
   of tyObject:
     IfFastObjectTypeCheckFailed(a, b):
       CycleCheck()
@@ -748,8 +750,9 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
     result = sameTuple(a, b, c)
   of tyGenericInst: result = sameTypeAux(lastSon(a), lastSon(b), c)
   of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence,
-     tyOrdinal, tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
-     tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter: 
+     tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
+     tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
+     tyOrdinal, tyTypeDesc, tyTypeClass:
     if sonsLen(a) == sonsLen(b):
       CycleCheck()
       result = true
@@ -845,7 +848,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
       result = typeAllowedAux(marker, t.sons[0], skResult)
   of tyExpr, tyStmt, tyTypeDesc: 
     result = true
-  of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation: 
+  of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation, tyTypeClass:
     result = false            #InternalError('shit found');
   of tyEmpty, tyNil:
     result = kind == skConst