summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2013-09-03 03:14:56 +0300
committerZahary Karadjov <zahary@gmail.com>2013-09-03 03:14:56 +0300
commit6082595e968f000b5089b1db7e72ad55bbf3fac3 (patch)
tree06a76e725c59524b5e7ab23e8c5f1a7c1bef5e54 /compiler
parent39da6979add895cf58e9c6f883ef8df465975cd6 (diff)
parentc8c8d2035af189bdf63b39d4e47266a6e67c38b9 (diff)
downloadNim-6082595e968f000b5089b1db7e72ad55bbf3fac3.tar.gz
Merge branch 'type-classes' into upstream
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim13
-rw-r--r--compiler/astalgo.nim13
-rw-r--r--compiler/evals.nim41
-rw-r--r--compiler/idents.nim1
-rw-r--r--compiler/lexer.nim4
-rw-r--r--compiler/msgs.nim3
-rw-r--r--compiler/parser.nim38
-rw-r--r--compiler/pragmas.nim7
-rw-r--r--compiler/sem.nim61
-rw-r--r--compiler/semcall.nim145
-rw-r--r--compiler/semdata.nim6
-rw-r--r--compiler/semexprs.nim124
-rw-r--r--compiler/semmagic.nim1
-rw-r--r--compiler/semstmts.nim11
-rw-r--r--compiler/semtypes.nim18
-rw-r--r--compiler/semtypinst.nim8
-rw-r--r--compiler/sigmatch.nim123
-rw-r--r--compiler/types.nim1
-rw-r--r--compiler/wordrecg.nim16
19 files changed, 430 insertions, 204 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index bb06e7163..6e0cafd74 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -178,6 +178,7 @@ type
     nkIncludeStmt,        # an include statement
     nkBindStmt,           # a bind statement
     nkMixinStmt,          # a mixin statement
+    nkUsingStmt,          # an using statement
     nkCommentStmt,        # a comment statement
     nkStmtListExpr,       # a statement list followed by an expr; this is used
                           # to allow powerful multi-line templates
@@ -190,6 +191,7 @@ type
     nkTypeOfExpr,         # type(1+2)
     nkObjectTy,           # object body
     nkTupleTy,            # tuple body
+    nkTypeClassTy,        # user-defined type class
     nkRecList,            # list of object parts
     nkRecCase,            # case section of object
     nkRecWhen,            # when section of object
@@ -215,7 +217,7 @@ type
   TNodeKinds* = set[TNodeKind]
 
 type
-  TSymFlag* = enum    # already 30 flags!
+  TSymFlag* = enum    # already 32 flags!
     sfUsed,           # read access of sym (for warnings) or simply used
     sfExported,       # symbol is exported from module
     sfFromGeneric,    # symbol is instantiation of a generic; this is needed 
@@ -352,6 +354,8 @@ type
                 # efficiency
     nfTransf,   # node has been transformed
     nfSem       # node has been checked for semantics
+    nfDelegate  # the call can use a delegator
+    nfExprCall  # this is an attempt to call a regular expression
 
   TNodeFlags* = set[TNodeFlag]
   TTypeFlag* = enum   # keep below 32 for efficiency reasons (now: 23)
@@ -616,6 +620,7 @@ type
   TScope* = object
     depthLevel*: int
     symbols*: TStrTable
+    usingSyms*: seq[PNode]
     parent*: PScope
 
   PScope* = ref TScope
@@ -688,6 +693,7 @@ type
                               # for enum types a list of symbols
                               # for tyInt it can be the int literal
                               # for procs and tyGenericBody, it's the
+                              # the body of the user-defined type class
                               # formal param list
                               # else: unused
     destructor*: PSym         # destructor. warning: nil here may not necessary
@@ -700,6 +706,7 @@ type
                               # -1 means that the size is unkwown
     align*: int               # the type's alignment requirements
     loc*: TLoc
+    testeeName*: PIdent       # the test variable in user-defined type classes
 
   TPair*{.final.} = object 
     key*, val*: PObject
@@ -771,7 +778,8 @@ const
     tyProc, tyString, tyError}
   ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator, 
     skMacro, skTemplate, skConverter, skEnumField, skLet, skStub}
-  PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfAllConst}
+  PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
+                                      nfAllConst, nfDelegate}
   namePos* = 0
   patternPos* = 1    # empty except for term rewriting macros
   genericParamsPos* = 2
@@ -1074,6 +1082,7 @@ proc assignType(dest, src: PType) =
   dest.size = src.size
   dest.align = src.align
   dest.destructor = src.destructor
+  dest.testeeName = src.testeeName
   # this fixes 'type TLock = TSysLock':
   if src.sym != nil:
     if dest.sym != nil:
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index fd6774e7a..6c48dd00f 100644
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -430,11 +430,14 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope =
     appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
     appf(result, "$N$1}", [spaces(indent)])
 
-proc debug(n: PSym) = 
-  #writeln(stdout, ropeToStr(symToYaml(n, 0, 1)))
-  writeln(stdout, ropeToStr(ropef("$1_$2: $3, $4", [
-    toRope(n.name.s), toRope(n.id), flagsToStr(n.flags), 
-    flagsToStr(n.loc.flags)])))
+proc debug(n: PSym) =
+  if n == nil:
+    writeln(stdout, "null")
+  else:
+    #writeln(stdout, ropeToStr(symToYaml(n, 0, 1)))
+    writeln(stdout, ropeToStr(ropef("$1_$2: $3, $4", [
+      toRope(n.name.s), toRope(n.id), flagsToStr(n.flags), 
+      flagsToStr(n.loc.flags)])))
 
 proc debug(n: PType) = 
   writeln(stdout, ropeToStr(debugType(n)))
diff --git a/compiler/evals.nim b/compiler/evals.nim
index 053068ea4..be6f625ec 100644
--- a/compiler/evals.nim
+++ b/compiler/evals.nim
@@ -53,7 +53,8 @@ type
     features: TSandboxFlags
     globals*: TIdNodeTable    # state of global vars
     getType*: proc(n: PNode): PNode {.closure.}
-  
+    handleIsOperator*: proc(n: PNode): PNode {.closure.}
+
   PEvalContext* = ref TEvalContext
 
   TEvalFlag = enum 
@@ -916,33 +917,6 @@ proc evalTypeTrait*(trait, operand: 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 and 
-                                        tfIterator notin t.flags))
-    of "iterator":
-      let t = skipTypes(t1, abstractRange)
-      result = newIntNode(nkIntLit, ord(t.kind == tyProc and
-                                        t.callConv == ccClosure and 
-                                        tfIterator in t.flags))
-  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 nkStrKinds:
     GlobalError(n.info, errStringLiteralExpected)
@@ -1038,7 +1012,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
     result = evalTypeTrait(n[0], operand, c.module)
   of mIs:
     n.sons[1] = evalAux(c, n.sons[1], {})
-    result = evalIsOp(n)
+    result = c.handleIsOperator(n)
   of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module)
   of mStaticExec:
     let cmd = evalAux(c, n.sons[1], {})
@@ -1466,8 +1440,7 @@ proc eval*(c: PEvalContext, n: PNode): PNode =
     else:
       stackTrace(c, result.info, errCannotInterpretNodeX, renderTree(n))
 
-proc evalConstExprAux(module, prc: PSym, e: PNode, mode: TEvalMode): PNode = 
-  var p = newEvalContext(module, mode)
+proc evalConstExprAux*(p: PEvalContext, module, prc: PSym, e: PNode): PNode =
   var s = newStackFrame()
   s.call = e
   s.prc = prc
@@ -1476,12 +1449,6 @@ proc evalConstExprAux(module, prc: PSym, e: PNode, mode: TEvalMode): PNode =
   if result != nil and result.kind == nkExceptBranch: result = nil
   popStackFrame(p)
 
-proc evalConstExpr*(module: PSym, e: PNode): PNode = 
-  result = evalConstExprAux(module, nil, e, emConst)
-
-proc evalStaticExpr*(module: PSym, e: PNode, prc: PSym): PNode = 
-  result = evalConstExprAux(module, prc, e, emStatic)
-
 proc setupMacroParam(x: PNode): PNode =
   result = x
   if result.kind == nkHiddenStdConv: result = result.sons[1]
diff --git a/compiler/idents.nim b/compiler/idents.nim
index a50c5269c..f0935c204 100644
--- a/compiler/idents.nim
+++ b/compiler/idents.nim
@@ -103,4 +103,5 @@ proc IdentEq*(id: PIdent, name: string): bool =
   result = id.id == getIdent(name).id
 
 var idAnon* = getIdent":anonymous"
+let idDelegator* = getIdent":delegator"
 
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index 6a104d139..82bfa0ad4 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -41,7 +41,7 @@ type
     tkGeneric, tkIf, tkImport, tkIn, tkInclude, tkInterface, 
     tkIs, tkIsnot, tkIterator,
     tkLambda, tkLet,
-    tkMacro, tkMethod, tkMixin, tkMod, tkNil, tkNot, tkNotin, 
+    tkMacro, tkMethod, tkMixin, tkUsing, tkMod, tkNil, tkNot, tkNotin, 
     tkObject, tkOf, tkOr, tkOut, 
     tkProc, tkPtr, tkRaise, tkRef, tkReturn, tkShared, tkShl, tkShr, tkStatic,
     tkTemplate, 
@@ -75,7 +75,7 @@ const
     "finally", "for", "from", "generic", "if", 
     "import", "in", "include", "interface", "is", "isnot", "iterator",
     "lambda", "let", 
-    "macro", "method", "mixin", "mod", 
+    "macro", "method", "mixin", "using", "mod", 
     "nil", "not", "notin", "object", "of", "or", 
     "out", "proc", "ptr", "raise", "ref", "return", 
     "shared", "shl", "shr", "static",
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index dd7bad943..5363442b4 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -92,6 +92,7 @@ type
     errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError, 
     errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile, 
     errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitely,
+    errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
     
     errXExpectsTwoArguments, 
     errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations, 
@@ -319,6 +320,8 @@ const
     errCannotRenderX: "cannot render reStructuredText element \'$1\'", 
     errVarVarTypeNotAllowed: "type \'var var\' is not allowed",
     errInstantiateXExplicitely: "instantiate '$1' explicitely",
+    errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator",
+    errUsingNoSymbol: "'$1' is not a variable, constant or a proc name",
     errXExpectsTwoArguments: "\'$1\' expects two arguments", 
     errXExpectsObjectTypes: "\'$1\' expects object types",
     errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype", 
diff --git a/compiler/parser.nim b/compiler/parser.nim
index bbacde1bf..0d9d27e02 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -927,9 +927,10 @@ proc parseExpr(p: var TParser): PNode =
   of tkTry: result = parseTry(p)
   else: result = simpleExpr(p)
 
+proc parseEnum(p: var TParser): PNode
 proc parseObject(p: var TParser): PNode
 proc parseDistinct(p: var TParser): PNode
-proc parseEnum(p: var TParser): PNode
+proc parseTypeClass(p: var TParser): PNode
 
 proc primary(p: var TParser, mode: TPrimaryMode): PNode = 
   #| typeKeyw = 'var' | 'ref' | 'ptr' | 'shared' | 'type' | 'tuple'
@@ -959,6 +960,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
   of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode)
   of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode)
   of tkShared: result = parseTypeDescKAux(p, nkSharedTy, mode)
+  of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, mode)
   of tkType: result = parseTypeDescKAux(p, nkTypeOfExpr, mode)
   of tkTuple: result = parseTuple(p, mode == pmTypeDef)
   of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
@@ -983,12 +985,11 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
     else:
       result = newNodeP(nkObjectTy, p)
       getTok(p)
-  of tkDistinct:
+  of tkGeneric:
     if mode == pmTypeDef:
-      result = parseDistinct(p)
+      result = parseTypeClass(p)
     else:
-      result = newNodeP(nkDistinctTy, p)
-      getTok(p)
+      parMessage(p, errInvalidToken, p.tok)
   of tkAddr:
     result = newNodeP(nkAddr, p)
     getTokNoInd(p)
@@ -1612,6 +1613,32 @@ proc parseObject(p: var TParser): PNode =
     return
   addSon(result, parseObjectPart(p))
 
+proc parseTypeClass(p: var TParser): PNode =
+  result = newNodeP(nkTypeClassTy, p)
+  getTok(p)
+  addSon(result, p.parseSymbol)
+  if p.tok.tokType == tkCurlyDotLe and p.validInd:
+    addSon(result, parsePragma(p))
+  else:
+    addSon(result, ast.emptyNode)
+  if p.tok.tokType == tkOf and p.tok.indent < 0:
+    var a = newNodeP(nkOfInherit, p)
+    getTok(p)
+    while true:
+      addSon(a, parseTypeDesc(p))
+      if p.tok.tokType != tkComma: break
+      getTok(p)
+    addSon(result, a)
+  else:
+    addSon(result, ast.emptyNode)
+  if p.tok.tokType == tkComment:
+    skipComment(p, result)
+  # an initial IND{>} HAS to follow:
+  if not realInd(p):
+    addSon(result, emptyNode)
+  else:
+    addSon(result, parseStmt(p))
+
 proc parseDistinct(p: var TParser): PNode = 
   #| distinct = 'distinct' optInd typeDesc
   result = newNodeP(nkDistinctTy, p)
@@ -1747,6 +1774,7 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
   of tkVar: result = parseSection(p, nkVarSection, parseVariable)
   of tkBind: result = parseBind(p, nkBindStmt)
   of tkMixin: result = parseBind(p, nkMixinStmt)
+  of tkUsing: result = parseBind(p, nkUsingStmt)
   else: result = simpleStmt(p)
   
 proc parseStmt(p: var TParser): PNode =
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index f185d0f80..aeffcdc4c 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -24,13 +24,14 @@ const
     wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge, 
     wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
     wNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
-    wGenSym, wInject, wRaises, wTags, wOperator}
+    wGenSym, wInject, wRaises, wTags, wOperator, wDelegator}
   converterPragmas* = procPragmas
   methodPragmas* = procPragmas
-  templatePragmas* = {wImmediate, wDeprecated, wError, wGenSym, wInject, wDirty}
+  templatePragmas* = {wImmediate, wDeprecated, wError, wGenSym, wInject, wDirty,
+    wDelegator}
   macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
     wNodecl, wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern,
-    wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject}
+    wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject, wDelegator}
   iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect, 
     wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
     wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject, wRaises,
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 4396a9093..71951dd3f 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -132,14 +132,42 @@ proc ParamsTypeCheck(c: PContext, typ: PType) {.inline.} =
     LocalError(typ.n.info, errXisNoType, typeToString(typ))
 
 proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
-
 proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode
-
-proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, 
-                  semCheck: bool = true): PNode
 proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
-
 proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode
+proc IsOpImpl(c: PContext, n: PNode): PNode
+proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
+                  semCheck: bool = true): PNode
+
+proc symFromType(t: PType, info: TLineInfo): PSym =
+  if t.sym != nil: return t.sym
+  result = newSym(skType, getIdent"AnonType", t.owner, info)
+  result.flags.incl sfAnon
+  result.typ = t
+
+proc symNodeFromType(c: PContext, t: PType, info: TLineInfo): PNode =
+  result = newSymNode(symFromType(t, info), info)
+  result.typ = makeTypeDesc(c, t)
+
+proc createEvalContext(c: PContext, mode: TEvalMode): PEvalContext =
+  result = newEvalContext(c.module, mode)
+  result.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.handleIsOperator = proc (n: PNode): PNode =
+    result = IsOpImpl(c, n)
+
+proc evalConstExpr(c: PContext, module: PSym, e: PNode): PNode = 
+  result = evalConstExprAux(c.createEvalContext(emConst), module, nil, e)
+
+proc evalStaticExpr(c: PContext, module: PSym, e: PNode, prc: PSym): PNode = 
+  result = evalConstExprAux(c.createEvalContext(emStatic), module, prc, e)
 
 proc semConstExpr(c: PContext, n: PNode): PNode =
   var e = semExprWithType(c, n)
@@ -148,7 +176,7 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
     return n
   result = getConstExpr(c.module, e)
   if result == nil:
-    result = evalConstExpr(c.module, e)
+    result = evalConstExpr(c, c.module, e)
     if result == nil or result.kind == nkEmpty:
       if e.info != n.info:
         pushInfoContext(n.info)
@@ -161,16 +189,6 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
 
 include hlo, seminst, semcall
 
-proc symFromType(t: PType, info: TLineInfo): PSym =
-  if t.sym != nil: return t.sym
-  result = newSym(skType, getIdent"AnonType", t.owner, info)
-  result.flags.incl sfAnon
-  result.typ = t
-
-proc symNodeFromType(c: PContext, t: PType, info: TLineInfo): PNode =
-  result = newSymNode(symFromType(t, info), info)
-  result.typ = makeTypeDesc(c, t)
-
 proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode = 
   inc(evalTemplateCounter)
   if evalTemplateCounter > 100:
@@ -205,15 +223,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
     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)
+    c.evalContext = c.createEvalContext(emStatic)
 
   result = evalMacroCall(c.evalContext, n, nOrig, sym)
   if semCheck: result = semAfterMacroCall(c, result, sym)
@@ -250,6 +260,7 @@ proc myOpen(module: PSym): PPassContext =
   if c.p != nil: InternalError(module.info, "sem.myOpen")
   c.semConstExpr = semConstExpr
   c.semExpr = semExpr
+  c.semTryExpr = tryExpr
   c.semOperand = semOperand
   c.semConstBoolExpr = semConstBoolExpr
   c.semOverloadedCall = semOverloadedCall
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index a29efcd8a..c8f150922 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -34,36 +34,35 @@ proc sameMethodDispatcher(a, b: PSym): bool =
   
 proc determineType(c: PContext, s: PSym)
 
-proc resolveOverloads(c: PContext, n, orig: PNode, 
-                      filter: TSymKinds): TCandidate =
-  var initialBinding: PNode
-  var f = n.sons[0]
-  if f.kind == nkBracketExpr:
-    # fill in the bindings:
-    initialBinding = f
-    f = f.sons[0]
-  else:
-    initialBinding = nil
-  
-  var
-    o: TOverloadIter
-    alt, z: TCandidate
-
-  template best: expr = result
-  #Message(n.info, warnUser, renderTree(n))
-  var sym = initOverloadIter(o, c, f)
+proc
+  pickBestCandidate(c: PContext, headSymbol: PNode,
+                    n, orig: PNode,
+                    initialBinding: PNode,
+                    filter: TSymKinds,
+                    best, alt: var TCandidate,
+                    errors: var seq[string]) =
+  var o: TOverloadIter
+  var sym = initOverloadIter(o, c, headSymbol)
   var symScope = o.lastOverloadScope
+
+  var z: TCandidate
   
   if sym == nil: return
   initCandidate(best, sym, initialBinding, symScope)
   initCandidate(alt, sym, initialBinding, symScope)
-
+  best.state = csNoMatch
+  
   while sym != nil:
     if sym.kind in filter:
       determineType(c, sym)
       initCandidate(z, sym, initialBinding, o.lastOverloadScope)
       z.calleeSym = sym
       matches(c, n, orig, z)
+      if errors != nil:
+        errors.safeAdd(getProcHeader(sym))
+        if z.errors != nil:
+          for err in z.errors:
+            errors[errors.len - 1].add("\n  " & err)
       if z.state == csMatch:
         # little hack so that iterators are preferred over everything else:
         if sym.kind == skIterator: inc(z.exactMatches, 200)
@@ -74,17 +73,100 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
           if cmp < 0: best = z   # x is better than the best so far
           elif cmp == 0: alt = z # x is as good as the best so far
           else: nil
-    sym = nextOverloadIter(o, c, f)
-
-  if best.state == csEmpty:
-    # no overloaded proc found
-    # do not generate an error yet; the semantic checking will check for
-    # an overloaded () operator
-  elif alt.state == csMatch and cmpCandidates(best, alt) == 0 and
-      not sameMethodDispatcher(best.calleeSym, alt.calleeSym):
-    if best.state != csMatch:
-      InternalError(n.info, "x.state is not csMatch")
-    #writeMatches(best)
+    sym = nextOverloadIter(o, c, headSymbol)
+
+proc NotFoundError*(c: PContext, n: PNode, errors: seq[string]) =
+  # 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, 1 + ord(nfDelegate in n.flags)))
+  add(result, ')')
+  
+  var candidates = ""
+  for err in errors:
+    add(candidates, err)
+    add(candidates, "\n")
+
+  if candidates != "":
+    add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
+
+  LocalError(n.Info, errGenerated, result)
+
+proc gatherUsedSyms(c: PContext, usedSyms: var seq[PNode]) =
+  for scope in walkScopes(c.currentScope):
+    if scope.usingSyms != nil:
+      for s in scope.usingSyms: usedSyms.safeAdd(s)
+
+proc resolveOverloads(c: PContext, n, orig: PNode,
+                      filter: TSymKinds): TCandidate =
+  var initialBinding: PNode
+  var alt: TCandidate
+  var f = n.sons[0]
+  if f.kind == nkBracketExpr:
+    # fill in the bindings:
+    initialBinding = f
+    f = f.sons[0]
+  else:
+    initialBinding = nil
+
+  var errors: seq[string]
+  var usedSyms: seq[PNode]
+ 
+  template pickBest(headSymbol: expr) =
+    pickBestCandidate(c, headSymbol, n, orig, initialBinding,
+                      filter, result, alt, errors)
+
+  gatherUsedSyms(c, usedSyms)
+  if usedSyms != nil:
+    var hiddenArg = if usedSyms.len > 1: newNode(nkClosedSymChoice, n.info, usedSyms)
+                    else: usedSyms[0]
+
+    n.sons.insert(hiddenArg, 1)
+    orig.sons.insert(hiddenArg, 1)
+    
+    pickBest(f)
+ 
+    if result.state != csMatch:
+      n.sons.delete(1)
+      orig.sons.delete(1)
+    else: return
+
+  pickBest(f)
+
+  let overloadsState = result.state
+  if overloadsState != csMatch:
+    if nfDelegate in n.flags:
+      InternalAssert f.kind == nkIdent
+      let calleeName = newStrNode(nkStrLit, f.ident.s)
+      calleeName.info = n.info
+
+      let callOp = newIdentNode(idDelegator, n.info)
+      n.sons[0..0] = [callOp, calleeName]
+      orig.sons[0..0] = [callOp, calleeName]
+     
+      pickBest(callOp)
+
+    if overloadsState == csEmpty and result.state == csEmpty:
+      LocalError(n.info, errUndeclaredIdentifier, considerAcc(f).s)
+      return
+    elif result.state != csMatch:
+      if nfExprCall in n.flags:
+        LocalError(n.info, errExprXCannotBeCalled,
+                   renderTree(n, {renderNoComments}))
+      else:
+        errors = @[]
+        pickBest(f)
+        NotFoundError(c, n, errors)
+      return
+
+  if alt.state == csMatch and cmpCandidates(result, alt) == 0 and
+      not sameMethodDispatcher(result.calleeSym, alt.calleeSym):
+    InternalAssert result.state == csMatch
+    #writeMatches(result)
     #writeMatches(alt)
     if c.inCompilesContext > 0: 
       # quick error message for performance of 'compiles' built-in:
@@ -98,7 +180,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
       add(args, ")")
 
       LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
-        getProcHeader(best.calleeSym), getProcHeader(alt.calleeSym),
+        getProcHeader(result.calleeSym), getProcHeader(alt.calleeSym),
         args])
 
 
@@ -155,6 +237,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
                        filter: TSymKinds): PNode =
   var r = resolveOverloads(c, n, nOrig, filter)
   if r.state == csMatch: result = semResolvedCall(c, n, r)
+  # else: result = errorNode(c, n)
     
 proc explicitGenericInstError(n: PNode): PNode =
   LocalError(n.info, errCannotInstantiateX, renderTree(n))
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 8b04f4af5..4c066f5fa 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -72,6 +72,7 @@ type
     libs*: TLinkedList         # all libs used by this module
     semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
     semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
+    semTryExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
     semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
     semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
     semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
@@ -204,6 +205,11 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType =
   result = newTypeS(tyTypeDesc, c)
   result.addSonSkipIntLit(typ.AssertNotNil)
 
+proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
+  let typedesc = makeTypeDesc(c, typ)
+  let sym = newSym(skType, idAnon, getCurrOwner(), info).linkTo(typedesc)
+  return newSymNode(sym, info)
+
 proc newTypeS(kind: TTypeKind, c: PContext): PType = 
   result = newType(kind, getCurrOwner())
 
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index d00490d2a..2681150e0 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -248,7 +248,11 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
     of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32: 
       # do not skip the range!
       n.typ = n.sons[1].typ.skipTypes(abstractVar)
-    else: LocalError(n.info, errInvalidArgForX, opToStr[m])
+    of tyGenericParam:
+      # leave it for now, it will be resolved in semtypinst
+      n.typ = getSysType(tyInt)
+    else:
+      LocalError(n.info, errInvalidArgForX, opToStr[m])
   result = n
 
 proc semSizeof(c: PContext, n: PNode): PNode =
@@ -295,6 +299,39 @@ proc semOf(c: PContext, n: PNode): PNode =
   n.typ = getSysType(tyBool)
   result = n
 
+proc IsOpImpl(c: PContext, 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.skipTypes({tyTypeDesc})
+
+  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 and 
+                                        tfIterator notin t.flags))
+    of "iterator":
+      let t = skipTypes(t1, abstractRange)
+      result = newIntNode(nkIntLit, ord(t.kind == tyProc and
+                                        t.callConv == ccClosure and 
+                                        tfIterator in t.flags))
+  else:
+    var match: bool
+    let t2 = n[2].typ
+    if t2.kind == tyTypeClass:
+      var m: TCandidate
+      InitCandidate(m, t2)
+      match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil
+    else:
+      match = sameType(t1, t2)
+ 
+    result = newIntNode(nkIntLit, ord(match))
+
+  result.typ = n.typ
+
 proc semIs(c: PContext, n: PNode): PNode =
   if sonsLen(n) != 3:
     LocalError(n.info, errXExpectsTwoArguments, "is")
@@ -303,21 +340,21 @@ proc semIs(c: PContext, n: PNode): PNode =
   n.typ = getSysType(tyBool)
   
   n.sons[1] = semExprWithType(c, n[1], {efDetermineType})
-  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:
+  if n[1].typ.kind != tyTypeDesc:
+    n.sons[1] = makeTypeSymNode(c, n[1].typ, n[1].info)
+  elif 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)
-  
+
+  let t1 = n[1].typ.sons[0]
+  # BUGFIX: don't evaluate this too early: ``T is void``
+  if not containsGenericType(t1): result = IsOpImpl(c, n)
+
 proc semOpAux(c: PContext, n: PNode) =
   const flags = {efDetermineType}
   for i in countup(1, n.sonsLen-1):
@@ -594,18 +631,18 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
       call.add(a)
     #echo "NOW evaluating at compile time: ", call.renderTree
     if sfCompileTime in callee.flags:
-      result = evalStaticExpr(c.module, call, c.p.owner)
+      result = evalStaticExpr(c, c.module, call, c.p.owner)
       if result.isNil: 
         LocalError(n.info, errCannotInterpretNodeX, renderTree(call))
     else:
-      result = evalConstExpr(c.module, call)
+      result = evalConstExpr(c, c.module, call)
       if result.isNil: result = n
     #if result != n:
     #  echo "SUCCESS evaluated at compile time: ", call.renderTree
 
 proc semStaticExpr(c: PContext, n: PNode): PNode =
   let a = semExpr(c, n.sons[0])
-  result = evalStaticExpr(c.module, a, c.p.owner)
+  result = evalStaticExpr(c, c.module, a, c.p.owner)
   if result.isNil:
     LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
     result = emptyNode
@@ -649,7 +686,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
       result = n.sons[0]
       result.kind = nkCall
       for i in countup(1, sonsLen(n) - 1): addSon(result, n.sons[i])
-      return semExpr(c, result, flags)
+      return semDirectOp(c, result, flags)
   else: 
     n.sons[0] = semExpr(c, n.sons[0])
   let nOrig = n.copyTree
@@ -699,14 +736,13 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
     # Now that nkSym does not imply an iteration over the proc/iterator space,
     # the old ``prc`` (which is likely an nkIdent) has to be restored:
     if result == nil: 
+      # XXX: hmm, what kind of symbols will end up here?
+      # do we really need to try the overload resolution?
       n.sons[0] = prc
       nOrig.sons[0] = prc
+      n.flags.incl nfExprCall
       result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
-    if result == nil:
-      if c.inCompilesContext > 0 or gErrorCounter == 0:
-        LocalError(n.info, errExprXCannotBeCalled,
-                   renderTree(n, {renderNoComments}))
-      return errorNode(c, n)
+      if result == nil: return errorNode(c, n)
   #result = afterCallActions(c, result, nOrig, flags)
   fixAbstractType(c, result)
   analyseIfAddressTakenInCall(c, result)
@@ -734,12 +770,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
   let nOrig = n.copyTree
   #semLazyOpAux(c, n)
   result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
-  if result == nil:
-    result = overloadedCallOpr(c, n)
-    if result == nil:
-      NotFoundError(c, n)
-      return errorNode(c, n)
-  result = afterCallActions(c, result, nOrig, flags)
+  if result != nil: result = afterCallActions(c, result, nOrig, flags)
 
 proc buildStringify(c: PContext, arg: PNode): PNode = 
   if arg.typ != nil and 
@@ -946,20 +977,11 @@ proc dotTransformation(c: PContext, n: PNode): PNode =
     addSon(result, copyTree(n[0]))
   else:
     var i = considerAcc(n.sons[1])
-    var f = searchInScopes(c, i)
-    # if f != nil and f.kind == skStub: loadStub(f)
-    # ``loadStub`` is not correct here as we don't care for ``f`` really
-    if f != nil: 
-      # BUGFIX: do not check for (f.kind in {skProc, skMethod, skIterator}) here
-      # This special node kind is to merge with the call handler in `semExpr`.
-      result = newNodeI(nkDotCall, n.info)
-      addSon(result, newIdentNode(i, n[1].info))
-      addSon(result, copyTree(n[0]))
-    else:
-      if not ContainsOrIncl(c.UnknownIdents, i.id):
-        LocalError(n.Info, errUndeclaredFieldX, i.s)
-      result = errorNode(c, n)
-
+    result = newNodeI(nkDotCall, n.info)
+    result.flags.incl nfDelegate
+    addSon(result, newIdentNode(i, n[1].info))
+    addSon(result, copyTree(n[0]))
+  
 proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = 
   # this is difficult, because the '.' is used in many different contexts
   # in Nimrod. We first allow types in the semantic checking.
@@ -1307,6 +1329,22 @@ proc newAnonSym(kind: TSymKind, info: TLineInfo,
   result = newSym(kind, idAnon, owner, info)
   result.flags = {sfGenSym}
 
+proc semUsing(c: PContext, n: PNode): PNode =
+  result = newNodeI(nkEmpty, n.info)
+  for e in n.sons:
+    let usedSym = semExpr(c, e)
+    if usedSym.kind == nkSym:
+      case usedSym.sym.kind
+      of skLocalVars + {skConst}:
+        c.currentScope.usingSyms.safeAdd(usedSym)
+        continue
+      of skProcKinds:
+        addDeclAt(c.currentScope, usedSym.sym)
+        continue
+      else: nil
+
+    LocalError(e.info, errUsingNoSymbol, e.renderTree)
+
 proc semExpandToAst(c: PContext, n: PNode): PNode =
   var macroCall = n[1]
   var expandedSym = expectMacroOrTemplateCall(c, macroCall)
@@ -1834,7 +1872,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: 
     # check if it is an expression macro:
     checkMinSonsLen(n, 1)
-    var s = qualifiedLookup(c, n.sons[0], {checkUndeclared})
+    let mode = if nfDelegate in n.flags: {} else: {checkUndeclared}
+    var s = qualifiedLookup(c, n.sons[0], mode)
     if s != nil: 
       case s.kind
       of skMacro:
@@ -1868,6 +1907,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     elif isSymChoice(n.sons[0]) or n[0].kind == nkBracketExpr and 
         isSymChoice(n[0][0]):
       result = semDirectOp(c, n, flags)
+    elif nfDelegate in n.flags:
+      result = semDirectOp(c, n, flags)
     else:
       result = semIndirectOp(c, n, flags)
   of nkWhen:
@@ -1943,6 +1984,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkForStmt, nkParForStmt: result = semFor(c, n)
   of nkCaseStmt: result = semCase(c, n)
   of nkReturnStmt: result = semReturn(c, n)
+  of nkUsingStmt: result = semUsing(c, n)
   of nkAsmStmt: result = semAsm(c, n)
   of nkYieldStmt: result = semYield(c, n)
   of nkPragma: pragma(c, c.p.owner, n, stmtPragmas)
@@ -1974,4 +2016,4 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   else:
     LocalError(n.info, errInvalidExpressionX,
                renderTree(n, {renderNoComments}))
-  incl(result.flags, nfSem)
+  if result != nil: incl(result.flags, nfSem)
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index b9ef8b008..88567b10a 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -113,6 +113,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
     result.typ = getSysType(tyString)
   of mInstantiationInfo: result = semInstantiationInfo(c, n)
   of mOrd: result = semOrd(c, n)
+  of mHigh: result = semLowHigh(c, n, mHigh)
   of mShallowCopy: result = semShallowCopy(c, n, flags)
   of mNBindSym: result = semBindSym(c, n)
   of mLocals: result = semLocals(c, n)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 7e69dbd92..0ce58ba5c 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -838,7 +838,14 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode =
     var it = n.sons[i]
     var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
     let m = lookupMacro(c, key)
-    if m == nil: continue
+    if m == nil:
+      if key.kind == nkIdent and key.ident.id == ord(wDelegator):
+        if considerAcc(prc.sons[namePos]).s == "()":
+          prc.sons[namePos] = newIdentNode(idDelegator, prc.info)
+          prc.sons[pragmasPos] = copyExcept(n, i)
+        else:
+          LocalError(prc.info, errOnlyACallOpCanBeDelegator)
+      continue
     # we transform ``proc p {.m, rest.}`` into ``m(do: proc p {.rest.})`` and
     # let the semantic checker deal with it:
     var x = newNodeI(nkCall, n.info)
@@ -1147,7 +1154,7 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
 
 proc semStaticStmt(c: PContext, n: PNode): PNode =
   let a = semStmt(c, n.sons[0])
-  result = evalStaticExpr(c.module, a, c.p.owner)
+  result = evalStaticExpr(c, c.module, a, c.p.owner)
   if result.isNil:
     LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
     result = emptyNode
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 14f96497d..64140274e 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -608,7 +608,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
       if genericParams.sons[i].sym.name.id == finalTypId.id:
         return genericParams.sons[i].typ
 
-    var s = newSym(skType, finalTypId, getCurrOwner(), info)
+    var s = newSym(skType, finalTypId, typeClass.sym, info)
     if typId == nil: s.flags.incl(sfAnon)
     s.linkTo(typeClass)
     s.position = genericParams.len
@@ -871,6 +871,21 @@ proc freshType(res, prev: PType): PType {.inline.} =
   else:
     result = res
 
+proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
+  # if n.sonsLen == 0: return newConstraint(c, tyTypeClass)
+  result = newOrPrevType(tyTypeClass, prev, c)
+  result.testeeName = considerAcc(n[0])
+  result.n = n[3]
+
+  let
+    pragmas = n[1]
+    inherited = n[2]
+    
+  if inherited.kind != nkEmpty:
+    for n in inherited.sons:
+      let typ = semTypeNode(c, n, nil)
+      result.sons.safeAdd(typ)
+
 proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   result = nil
   if gCmd == cmdIdeTools: suggestExpr(c, n)
@@ -973,6 +988,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
       result = newOrPrevType(tyError, prev, c)
   of nkObjectTy: result = semObjectNode(c, n, prev)
   of nkTupleTy: result = semTuple(c, n, prev)
+  of nkTypeClassTy: result = semTypeClass(c, n, prev)
   of nkRefTy: result = semAnyRef(c, n, tyRef, prev)
   of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
   of nkVarTy: result = semVarType(c, n, prev)
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 0c15c7248..b638449d2 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -148,12 +148,13 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
   if result != nil: return
   for i in countup(1, sonsLen(t) - 1):
     var x = t.sons[i]
-    if x.kind == tyGenericParam: 
+    if x.kind == tyGenericParam:
       x = lookupTypeVar(cl, x)
       if header == nil: header = copyType(t, t.owner, false)
       header.sons[i] = x
       propagateToOwner(header, x)
-      #idTablePut(cl.typeMap, body.sons[i-1], x)
+      #idTablePut(cl.typeMap, body.sons[i-1], x)  
+
   if header != nil:
     # search again after first pass:
     result = searchInstTypes(header)
@@ -200,6 +201,9 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
     result = lookupTypeVar(cl, t)
     if result.kind == tyGenericInvokation:
       result = handleGenericInvokation(cl, result)
+  of tyExpr:
+    if t.sym != nil and t.sym.kind == skGenericParam:
+      result = lookupTypeVar(cl, t)
   of tyGenericInvokation: 
     result = handleGenericInvokation(cl, t)
   of tyGenericBody:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index b331a08e5..318acc660 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -40,7 +40,9 @@ type
                              # be instantiated
     typedescMatched: bool
     inheritancePenalty: int  # to prefer closest father object type
-  
+    errors*: seq[string]     # additional clarifications to be displayed to the
+                             # user if overload resolution fails
+
   TTypeRelation* = enum      # order is important!
     isNone, isConvertible,
     isIntConv,
@@ -200,28 +202,6 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string =
     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
-  var sym = initOverloadIter(o, c, n.sons[0])
-  while sym != nil:
-    if sym.kind in RoutineKinds:
-      add(candidates, getProcHeader(sym))
-      add(candidates, "\n")
-    sym = nextOverloadIter(o, c, n.sons[0])
-  if candidates != "":
-    add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
-  LocalError(n.Info, errGenerated, result)
-  
 proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation
 proc concreteType(c: TCandidate, t: PType): PType = 
   case t.kind
@@ -643,7 +623,10 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
         else:
           result = isNone
       else:
-        result = matchTypeClass(c, f, a)
+        if a.kind == tyTypeClass:
+          result = isGeneric
+        else:
+          result = matchTypeClass(c, f, a)
         
       if result == isGeneric:
         var concrete = concreteType(c, a)
@@ -754,35 +737,93 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
       result.typ = getInstantiatedType(c, arg, m, base(f))
     m.baseTypeMatch = true
 
+proc matchUserTypeClass*(c: PContext, m: var TCandidate,
+                         arg: PNode, f, a: PType): PNode =
+  if f.n == nil:
+    let r = typeRel(m, f, a)
+    return if r == isGeneric: arg else: nil
+ 
+  var prev = PType(idTableGet(m.bindings, f))
+  if prev != nil:
+    if sameType(prev, a): return arg
+    else: return nil
+
+  # pushInfoContext(arg.info)
+  openScope(c)
+
+  var testee = newSym(skParam, f.testeeName, f.sym, f.sym.info)
+  testee.typ = a
+  addDecl(c, testee)
+
+  for stmt in f.n:
+    var e = c.semTryExpr(c, copyTree(stmt))
+    if e == nil:
+      let expStr = renderTree(stmt, {renderNoComments})
+      m.errors.safeAdd("can't compile " & expStr & "  for " & a.typeToString)
+      return nil
+    case e.kind
+    of nkReturnStmt:
+      nil
+    of nkTypeSection: nil
+    of nkConstDef: nil
+    else:
+      if e.typ.kind == tyBool:
+        let verdict = c.semConstExpr(c, e)
+        if verdict.intVal == 0:
+          let expStr = renderTree(stmt, {renderNoComments})
+          m.errors.safeAdd(expStr & " doesn't hold for " & a.typeToString)
+          return nil
+
+  closeScope(c)
+
+  result = arg
+  put(m.bindings, f, a)
+
 proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType, 
-                        arg, argOrig: PNode): PNode =
+                        argSemantized, argOrig: PNode): PNode =
+  var arg = argSemantized
   var r: TTypeRelation
   let fMaybeExpr = f.skipTypes({tyDistinct})
-  if fMaybeExpr.kind == tyExpr:
+  case fMaybeExpr.kind
+  of tyExpr:
     if fMaybeExpr.sonsLen == 0:
       r = isGeneric
     else:
-      let match = matchTypeClass(m, fMaybeExpr, a)
-      if match != isGeneric: r = isNone
+      if a.kind == tyExpr:
+        InternalAssert a.len > 0
+        r = typeRel(m, f.lastSon, a.lastSon)
       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.sons = @[evaluated.typ]
-          arg.typ.n = evaluated
+        let match = matchTypeClass(m, fMaybeExpr, 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.sons = @[evaluated.typ]
+            arg.typ.n = evaluated
         
     if r == isGeneric:
       put(m.bindings, f, arg.typ)
+  of tyTypeClass:
+    if fMaybeExpr.n != nil:
+      let match = matchUserTypeClass(c, m, arg, fMaybeExpr, a)
+      if match != nil:
+        r = isGeneric
+        arg = match
+      else:
+        r = isNone
+    else:
+      r = typeRel(m, f, a)
   else:
     r = typeRel(m, f, a)
-  
+
   case r
   of isConvertible: 
     inc(m.convMatches)
diff --git a/compiler/types.nim b/compiler/types.nim
index 084091630..f9c40e201 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -445,6 +445,7 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
     if t.len == 0: result = "typedesc"
     else: result = "typedesc[" & constraintsToStr(t) & "]"
   of tyTypeClass:
+    if t.n != nil: return t.sym.owner.name.s
     case t.len
     of 0: result = "typeclass[]"
     of 1: result = "typeclass[" & consToStr(t.sons[0]) & "]"
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index a9540269c..b37a7bb4f 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -28,7 +28,7 @@ type
     wElif, wElse, wEnd, wEnum, wExcept, wExport,
     wFinally, wFor, wFrom, wGeneric, wIf, wImport, wIn, 
     wInclude, wInterface, wIs, wIsnot, wIterator, wLambda, wLet,
-    wMacro, wMethod, wMixin, wMod, wNil, 
+    wMacro, wMethod, wMixin, wUsing, wMod, wNil, 
     wNot, wNotin, wObject, wOf, wOr, wOut, wProc, wPtr, wRaise, wRef, wReturn, 
     wShared, wShl, wShr, wStatic, wTemplate, wTry, wTuple, wType, wVar, 
     wWhen, wWhile, wWith, wWithout, wXor, wYield,
@@ -39,7 +39,8 @@ type
 
     wDestroy,
     
-    wImmediate, wDestructor, wImportCpp, wImportObjC,
+    wImmediate, wDestructor, wDelegator,
+    wImportCpp, wImportObjC,
     wImportCompilerProc,
     wImportc, wExportc, wIncompleteStruct, wRequiresInit,
     wAlign, wNodecl, wPure, wSideeffect, wHeader,
@@ -71,7 +72,7 @@ type
     wPrivate, wProtected, wPublic, wRegister, wReinterpret_cast,
     wShort, wSigned, wSizeof, wStatic_cast, wStruct, wSwitch,
     wThis, wThrow, wTrue, wTypedef, wTypeid, wTypename,
-    wUnion, wUnsigned, wUsing, wVirtual, wVoid, wVolatile, wWchar_t,
+    wUnion, wUnsigned, wVirtual, wVoid, wVolatile, wWchar_t,
 
     wAlignas, wAlignof, wConstexpr, wDecltype, wNullptr, wNoexcept,
     wThread_local, wStatic_assert, wChar16_t, wChar32_t,
@@ -94,7 +95,7 @@ const
   
   cppNimSharedKeywords* = {
     wAsm, wBreak, wCase, wConst, wContinue, wDo, wElse, wEnum, wExport,
-    wFor, wIf, wReturn, wStatic, wTemplate, wTry, wWhile}
+    wFor, wIf, wReturn, wStatic, wTemplate, wTry, wWhile, wUsing }
 
   specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["", 
     
@@ -106,7 +107,7 @@ const
     "finally", "for", "from", "generic", "if", 
     "import", "in", "include", "interface", "is", "isnot", "iterator",
     "lambda", "let",
-    "macro", "method", "mixin", "mod", "nil", "not", "notin", 
+    "macro", "method", "mixin", "using", "mod", "nil", "not", "notin",
     "object", "of", "or", 
     "out", "proc", "ptr", "raise", "ref", "return",
     "shared", "shl", "shr", "static",
@@ -120,7 +121,8 @@ const
 
     "destroy",
     
-    "immediate", "destructor", "importcpp", "importobjc",
+    "immediate", "destructor", "delegator",
+    "importcpp", "importobjc",
     "importcompilerproc", "importc", "exportc", "incompletestruct",
     "requiresinit", "align", "nodecl", "pure", "sideeffect",
     "header", "nosideeffect", "noreturn", "merge", "lib", "dynlib", 
@@ -152,7 +154,7 @@ const
     "private", "protected", "public", "register", "reinterpret_cast",
     "short", "signed", "sizeof", "static_cast", "struct", "switch",
     "this", "throw", "true", "typedef", "typeid",
-    "typename", "union", "unsigned", "using", "virtual", "void", "volatile",
+    "typename", "union", "unsigned", "virtual", "void", "volatile",
     "wchar_t",
 
     "alignas", "alignof", "constexpr", "decltype", "nullptr", "noexcept",