summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim2
-rw-r--r--compiler/extccomp.nim2
-rw-r--r--compiler/msgs.nim55
-rw-r--r--compiler/parser.nim15
-rw-r--r--compiler/sem.nim3
-rw-r--r--compiler/semdata.nim4
-rw-r--r--compiler/semexprs.nim30
-rw-r--r--compiler/semstmts.nim39
-rw-r--r--compiler/semtypes.nim3
-rw-r--r--compiler/sigmatch.nim68
-rw-r--r--doc/gc.txt2
-rw-r--r--doc/lib.txt2
-rw-r--r--doc/manual.txt31
-rw-r--r--doc/tut1.txt8
-rw-r--r--lib/packages/docutils/rst.nim10
-rw-r--r--lib/pure/httpserver.nim5
-rw-r--r--lib/pure/irc.nim8
-rw-r--r--lib/pure/oids.nim6
-rw-r--r--lib/pure/sockets.nim3
-rw-r--r--lib/pure/times.nim3
-rw-r--r--lib/pure/unicode.nim30
-rw-r--r--lib/system/alloc.nim15
-rw-r--r--lib/system/gc.nim21
-rw-r--r--lib/system/gc2.nim3
-rw-r--r--lib/system/mmdisp.nim1
-rw-r--r--tests/run/tstaticparams.nim9
-rw-r--r--tests/run/tusertypeclasses.nim28
27 files changed, 275 insertions, 131 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 2a7d8a551..5a5d87d06 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -712,7 +712,6 @@ 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
@@ -1088,7 +1087,6 @@ 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/extccomp.nim b/compiler/extccomp.nim
index d7f3386e3..13eb972f6 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -583,7 +583,7 @@ proc CallCCompiler*(projectfile: string) =
       else:
         rawMessage(errGenerated, " execution of an external program failed; " &
                    "rerun with --parallelBuild:1 to see the error message")
-  if optNoLinking notin gGlobalOptions and cmds.len > 0:
+  if optNoLinking notin gGlobalOptions:
     # call the linker:
     var it = PStrEntry(toLink.head)
     var objfiles = ""
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 5363442b4..895ba71f3 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -436,7 +436,14 @@ type
                                # only 8 bytes.
     line*, col*: int16
     fileIndex*: int32
-    
+  
+  TErrorOutput* = enum
+    eStdOut
+    eStdErr
+    eInMemory
+
+  TErrorOutputs* = set[TErrorOutput]
+
   ERecoverableError* = object of EInvalidValue
   ESuggestDone* = object of EBase
 
@@ -534,13 +541,27 @@ var
   gHintCounter*: int = 0
   gWarnCounter*: int = 0
   gErrorMax*: int = 1         # stop after gErrorMax errors
-  gSilence*: int              # == 0 if we produce any output at all 
 
 when useCaas:
   var stdoutSocket*: TSocket
 
+proc UnknownLineInfo*(): TLineInfo =
+  result.line = int16(-1)
+  result.col = int16(-1)
+  result.fileIndex = -1
+
+var 
+  msgContext: seq[TLineInfo] = @[]
+  lastError = UnknownLineInfo()
+  bufferedMsgs*: seq[string]
+
+  errorOutputs* = {eStdOut, eStdErr}
+
+proc clearBufferedMsgs* =
+  bufferedMsgs = nil
+
 proc SuggestWriteln*(s: string) =
-  if gSilence == 0:
+  if eStdOut in errorOutputs:
     when useCaas:
       if isNil(stdoutSocket): Writeln(stdout, s)
       else:
@@ -548,6 +569,9 @@ proc SuggestWriteln*(s: string) =
         stdoutSocket.send(s & "\c\L")
     else:
       Writeln(stdout, s)
+  
+  if eInMemory in errorOutputs:
+    bufferedMsgs.safeAdd(s)
 
 proc SuggestQuit*() =
   if not isServing:
@@ -570,14 +594,6 @@ const
   RawWarningFormat* = "Warning: $1"
   RawHintFormat* = "Hint: $1"
 
-proc UnknownLineInfo*(): TLineInfo = 
-  result.line = int16(-1)
-  result.col = int16(-1)
-  result.fileIndex = -1
-
-var 
-  msgContext: seq[TLineInfo] = @[]
-
 proc getInfoContextLen*(): int = return msgContext.len
 proc setInfoContextLen*(L: int) = setLen(msgContext, L)
 
@@ -642,14 +658,18 @@ proc addCheckpoint*(filename: string, line: int) =
 
 proc OutWriteln*(s: string) = 
   ## Writes to stdout. Always.
-  if gSilence == 0: Writeln(stdout, s)
+  if eStdOut in errorOutputs: Writeln(stdout, s)
  
 proc MsgWriteln*(s: string) = 
   ## Writes to stdout. If --stdout option is given, writes to stderr instead.
-  if gSilence == 0:
-    if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
-    if optStdout in gGlobalOptions: Writeln(stderr, s)
-    else: Writeln(stdout, s)
+  if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
+
+  if optStdout in gGlobalOptions:
+    if eStdErr in errorOutputs: Writeln(stderr, s)
+  else:
+    if eStdOut in errorOutputs: Writeln(stdout, s)
+  
+  if eInMemory in errorOutputs: bufferedMsgs.safeAdd(s)
 
 proc coordToStr(coord: int): string = 
   if coord == -1: result = "???"
@@ -736,9 +756,6 @@ proc rawMessage*(msg: TMsgKind, args: openarray[string]) =
 proc rawMessage*(msg: TMsgKind, arg: string) = 
   rawMessage(msg, [arg])
 
-var
-  lastError = UnknownLineInfo()
-
 proc writeSurroundingSrc(info: TLineInfo) =
   const indent = "  "
   MsgWriteln(indent & info.sourceLine.ropeToStr)
diff --git a/compiler/parser.nim b/compiler/parser.nim
index e8439466a..fd51b04ec 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -1624,10 +1624,23 @@ proc parseObject(p: var TParser): PNode =
     return
   addSon(result, parseObjectPart(p))
 
+proc parseTypeClassParam(p: var TParser): PNode =
+  if p.tok.tokType == tkVar:
+    getTok(p)
+    result = newNode(nkVarTy)
+    result.addSon(p.parseSymbol)
+  else:
+    result = p.parseSymbol
+
 proc parseTypeClass(p: var TParser): PNode =
   result = newNodeP(nkTypeClassTy, p)
   getTok(p)
-  addSon(result, p.parseSymbol)
+  var args = newNode(nkArgList)
+  addSon(result, args)
+  addSon(args, p.parseTypeClassParam)
+  while p.tok.TokType == tkComma:
+    getTok(p)
+    addSon(args, p.parseTypeClassParam)
   if p.tok.tokType == tkCurlyDotLe and p.validInd:
     addSon(result, parsePragma(p))
   else:
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 71951dd3f..ea53afbeb 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -36,7 +36,8 @@ proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
 proc addParams(c: PContext, n: PNode, kind: TSymKind)
 proc maybeAddResult(c: PContext, s: PSym, n: PNode)
 proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
-proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
+proc tryExpr(c: PContext, n: PNode,
+             flags: TExprFlags = {}, bufferErrors = false): PNode
 proc fixImmediateParams(n: PNode): PNode
 proc activate(c: PContext, n: PNode)
 proc semQuoteAst(c: PContext, n: PNode): PNode
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 121bf297d..d02359d4c 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -60,6 +60,7 @@ type
     threadEntries*: TSymSeq    # list of thread entries to check
     AmbiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot
                                # store this info in the syms themselves!)
+    InTypeClass*: int          # > 0 if we are in a user-defined type class
     InGenericContext*: int     # > 0 if we are in a generic type
     InUnrolledContext*: int    # > 0 if we are unrolling a loop
     InCompilesContext*: int    # > 0 if we are in a ``compiles`` magic
@@ -72,7 +73,8 @@ 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.}
+    semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {},
+                       bufferErrors = false): 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,
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 47e07d402..337224aef 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -299,7 +299,7 @@ proc semOf(c: PContext, n: PNode): PNode =
   n.typ = getSysType(tyBool)
   result = n
 
-proc IsOpImpl(c: PContext, n: PNode): PNode =
+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}
@@ -321,10 +321,19 @@ proc IsOpImpl(c: PContext, n: PNode): PNode =
   else:
     var match: bool
     let t2 = n[2].typ
-    if t2.kind == tyTypeClass:
+    case t2.kind
+    of tyTypeClass:
       var m: TCandidate
       InitCandidate(m, t2)
       match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil
+    of tyOrdinal:
+      var m: TCandidate
+      InitCandidate(m, t2)
+      match = isOrdinalType(t1)
+    of tySequence, tyArray, tySet:
+      var m: TCandidate
+      InitCandidate(m, t2)
+      match = typeRel(m, t2, t1) != isNone
     else:
       match = sameType(t1, t2)
  
@@ -353,7 +362,7 @@ proc semIs(c: PContext, n: PNode): PNode =
 
   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)
+  if not containsGenericType(t1): result = isOpImpl(c, n)
 
 proc semOpAux(c: PContext, n: PNode) =
   const flags = {efDetermineType}
@@ -763,7 +772,8 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
     analyseIfAddressTakenInCall(c, result)
     if callee.magic != mNone:
       result = magicsAfterOverloadResolution(c, result, flags)
-  result = evalAtCompileTime(c, result)
+  if c.InTypeClass == 0:
+    result = evalAtCompileTime(c, result)
 
 proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = 
   # this seems to be a hotspot in the compiler!
@@ -814,7 +824,7 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode =
 
 proc semExprNoType(c: PContext, n: PNode): PNode =
   result = semExpr(c, n, {efWantStmt})
-  discardCheck(result)
+  discardCheck(c, result)
   
 proc isTypeExpr(n: PNode): bool = 
   case n.kind
@@ -1208,7 +1218,7 @@ proc semProcBody(c: PContext, n: PNode): PNode =
       a.sons[1] = result
       result = semAsgn(c, a)
   else:
-    discardCheck(result)
+    discardCheck(c, result)
   closeScope(c)
 
 proc SemYieldVarResult(c: PContext, n: PNode, restype: PType) =
@@ -1429,12 +1439,12 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
     newNode(nkCall, n.info, quotes)])
   result = semExpandToAst(c, result)
 
-proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
+proc tryExpr(c: PContext, n: PNode,
+             flags: TExprFlags = {}, bufferErrors = false): PNode =
   # watch out, hacks ahead:
   let oldErrorCount = msgs.gErrorCounter
   let oldErrorMax = msgs.gErrorMax
   inc c.InCompilesContext
-  inc msgs.gSilence
   # do not halt after first error:
   msgs.gErrorMax = high(int)
   
@@ -1443,6 +1453,8 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   openScope(c)
   let oldOwnerLen = len(gOwners)
   let oldGenerics = c.generics
+  let oldErrorOutputs = errorOutputs
+  errorOutputs = if bufferErrors: {eInMemory} else: {}
   let oldContextLen = msgs.getInfoContextLen()
   
   let oldInGenericContext = c.InGenericContext
@@ -1465,7 +1477,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   setlen(gOwners, oldOwnerLen)
   c.currentScope = oldScope
   dec c.InCompilesContext
-  dec msgs.gSilence
+  errorOutputs = oldErrorOutputs
   msgs.gErrorCounter = oldErrorCount
   msgs.gErrorMax = oldErrorMax
 
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index ed6787a16..da8ba50a8 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -132,7 +132,7 @@ proc fixNilType(n: PNode) =
     for it in n: fixNilType(it)
   n.typ = nil
 
-proc discardCheck(result: PNode) =
+proc discardCheck(c: PContext, result: PNode) =
   if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}:
     if result.kind == nkNilLit:
       result.typ = nil
@@ -142,6 +142,10 @@ proc discardCheck(result: PNode) =
       while n.kind in skipForDiscardable:
         n = n.lastSon
         n.typ = nil
+    elif c.InTypeClass > 0 and result.typ.kind == tyBool:
+      let verdict = semConstExpr(c, result)
+      if verdict.intVal == 0:
+        localError(result.info, "type class predicate failed.")
     elif result.typ.kind != tyError and gCmd != cmdInteractive:
       if result.typ.kind == tyNil:
         fixNilType(result)
@@ -169,7 +173,7 @@ proc semIf(c: PContext, n: PNode): PNode =
       typ = commonType(typ, it.sons[0].typ)
     else: illFormedAst(it)
   if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
-    for it in n: discardCheck(it.lastSon)
+    for it in n: discardCheck(c, it.lastSon)
     result.kind = nkIfStmt
     # propagate any enforced VoidContext:
     if typ == EnforceVoidContext: result.typ = EnforceVoidContext
@@ -230,7 +234,7 @@ proc semCase(c: PContext, n: PNode): PNode =
       localError(n.info, errNotAllCasesCovered)
   closeScope(c)
   if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
-    for i in 1..n.len-1: discardCheck(n.sons[i].lastSon)
+    for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
     # propagate any enforced VoidContext:
     if typ == EnforceVoidContext:
       result.typ = EnforceVoidContext
@@ -275,8 +279,8 @@ proc semTry(c: PContext, n: PNode): PNode =
     typ = commonType(typ, a.sons[length-1].typ)
   dec c.p.inTryStmt
   if isEmptyType(typ) or typ.kind == tyNil:
-    discardCheck(n.sons[0])
-    for i in 1..n.len-1: discardCheck(n.sons[i].lastSon)
+    discardCheck(c, n.sons[0])
+    for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
     if typ == EnforceVoidContext:
       result.typ = EnforceVoidContext
   else:
@@ -879,8 +883,9 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
   openScope(c)
   if n.sons[genericParamsPos].kind != nkEmpty:
     illFormedAst(n)           # process parameters:
-  if n.sons[paramsPos].kind != nkEmpty: 
-    semParamList(c, n.sons[ParamsPos], nil, s)
+  if n.sons[paramsPos].kind != nkEmpty:
+    var gp = newNodeI(nkGenericParams, n.info)
+    semParamList(c, n.sons[ParamsPos], gp, s)
     ParamsTypeCheck(c, s.typ)
   else:
     s.typ = newTypeS(tyProc, c)
@@ -1104,24 +1109,24 @@ proc finishMethod(c: PContext, s: PSym) =
     methodDef(s, false)
 
 proc semMethod(c: PContext, n: PNode): PNode = 
-  if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "method")
+  if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method")
   result = semProcAux(c, n, skMethod, methodPragmas)
   
   var s = result.sons[namePos].sym
-  if not isGenericRoutine(s):
+  if not isGenericRoutine(s) and result.sons[bodyPos].kind != nkEmpty:
     if hasObjParam(s):
-      methodDef(s, false)
+      methodDef(s, fromCache=false)
     else:
-      LocalError(n.info, errXNeedsParamObjectType, "method")
+      localError(n.info, errXNeedsParamObjectType, "method")
 
 proc semConverterDef(c: PContext, n: PNode): PNode = 
-  if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "converter")
+  if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter")
   checkSonsLen(n, bodyPos + 1)
   result = semProcAux(c, n, skConverter, converterPragmas)
   var s = result.sons[namePos].sym
   var t = s.typ
-  if t.sons[0] == nil: LocalError(n.info, errXNeedsReturnType, "converter")
-  if sonsLen(t) != 2: LocalError(n.info, errXRequiresOneArgument, "converter")
+  if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "converter")
+  if sonsLen(t) != 2: localError(n.info, errXRequiresOneArgument, "converter")
   addConverter(c, s)
 
 proc semMacroDef(c: PContext, n: PNode): PNode = 
@@ -1129,9 +1134,9 @@ proc semMacroDef(c: PContext, n: PNode): PNode =
   result = semProcAux(c, n, skMacro, macroPragmas)
   var s = result.sons[namePos].sym
   var t = s.typ
-  if t.sons[0] == nil: LocalError(n.info, errXNeedsReturnType, "macro")
+  if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro")
   if n.sons[bodyPos].kind == nkEmpty:
-    LocalError(n.info, errImplOfXexpected, s.name.s)
+    localError(n.info, errImplOfXexpected, s.name.s)
   
 proc evalInclude(c: PContext, n: PNode): PNode =
   result = newNodeI(nkStmtList, n.info)
@@ -1221,7 +1226,7 @@ proc semStmtList(c: PContext, n: PNode): PNode =
         voidContext = true
         n.typ = EnforceVoidContext
       if i != last or voidContext:
-        discardCheck(n.sons[i])
+        discardCheck(c, n.sons[i])
       else:
         n.typ = n.sons[i].typ
         if not isEmptyType(n.typ):
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index b9893d037..92f47f585 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -876,8 +876,7 @@ proc freshType(res, prev: PType): PType {.inline.} =
 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]
+  result.n = n
 
   let
     pragmas = n[1]
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 318acc660..00f3b2b10 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -85,6 +85,7 @@ proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode,
   c.calleeSym = callee
   c.calleeScope = calleeScope
   initIdTable(c.bindings)
+  c.errors = nil
   if binding != nil and callee.kind in RoutineKinds:
     var typeParams = callee.ast[genericParamsPos]
     for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1):
@@ -202,7 +203,7 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string =
     add(result, argTypeToString(arg))
     if i != sonsLen(n) - 1: add(result, ", ")
 
-proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation
+proc typeRel*(c: var TCandidate, f, a: PType): TTypeRelation
 proc concreteType(c: TCandidate, t: PType): PType = 
   case t.kind
   of tyArrayConstr: 
@@ -750,40 +751,55 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
 
   # pushInfoContext(arg.info)
   openScope(c)
+  inc c.InTypeClass
 
-  var testee = newSym(skParam, f.testeeName, f.sym, f.sym.info)
-  testee.typ = a
-  addDecl(c, testee)
+  finally:
+    dec c.InTypeClass
+    closeScope(c)
 
-  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
+  for param in f.n[0]:
+    var
+      dummyName: PNode
+      dummyType: PType
+    
+    if param.kind == nkVarTy:
+      dummyName = param[0]
+      dummyType = makeVarType(c, a)
     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
+      dummyName = param
+      dummyType = a
+
+    InternalAssert dummyName.kind == nkIdent
+    var dummyParam = newSym(skType, dummyName.ident, f.sym, f.sym.info)
+    dummyParam.typ = dummyType
+    addDecl(c, dummyParam)
 
-  closeScope(c)
+  for stmt in f.n[3]:
+    var e = c.semTryExpr(c, copyTree(stmt), bufferErrors = false)
+    m.errors = bufferedMsgs
+    clearBufferedMsgs()
+    if e == nil: return nil
 
+    case e.kind
+    of nkReturnStmt: nil
+    of nkTypeSection: nil
+    of nkConstDef: nil
+    else: nil
+  
   result = arg
   put(m.bindings, f, a)
 
-proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType, 
+proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, argType: PType,
                         argSemantized, argOrig: PNode): PNode =
-  var arg = argSemantized
-  var r: TTypeRelation
-  let fMaybeExpr = f.skipTypes({tyDistinct})
+  var
+    r: TTypeRelation
+    arg = argSemantized
+
+  let
+    a = if c.InTypeClass > 0: argType.skipTypes({tyTypeDesc})
+        else: argType
+    fMaybeExpr = f.skipTypes({tyDistinct})
+
   case fMaybeExpr.kind
   of tyExpr:
     if fMaybeExpr.sonsLen == 0:
diff --git a/doc/gc.txt b/doc/gc.txt
index 854f9ce2a..13498afaa 100644
--- a/doc/gc.txt
+++ b/doc/gc.txt
@@ -13,7 +13,7 @@ Introduction
 This document describes how the GC works and how to tune it for
 (soft) `realtime systems`:idx:.
 
-The basic algorithm is *Deferrent Reference Counting* with cycle detection.
+The basic algorithm is *Deferred Reference Counting* with cycle detection.
 References on the stack are not counted for better performance (and easier C
 code generation). The GC **never** scans the whole heap but it may scan the
 delta-subgraph of the heap that changed since its last run.
diff --git a/doc/lib.txt b/doc/lib.txt
index 1b004aa9d..92a4a7c83 100644
--- a/doc/lib.txt
+++ b/doc/lib.txt
@@ -64,6 +64,8 @@ Core
 Collections and algorithms
 --------------------------
 
+* `algorithm <algorithm.html>`_
+  Implements some common generic algorithms like sort or binary search.
 * `tables <tables.html>`_
   Nimrod hash table support. Contains tables, ordered tables and count tables.
 * `sets <sets.html>`_
diff --git a/doc/manual.txt b/doc/manual.txt
index c63df0304..dabff3d69 100644
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -3289,27 +3289,36 @@ Declarative type classes are written in the following form:
       for value in c:
         type(value) is T
 
-
-The identifiers following the `generic` keyword are treated as variables of
-the matched type and the body of the type class consists of arbitrary code that
-must be valid under these circumstances.
-
-Specifically, the type class will be matched if:
+The type class will be matched if:
 
 a) all of the expressions within the body can be compiled for the tested type
 b) all statically evaluatable boolean expressions in the body must be true
 
-Please note that the ``is`` operator allows you to easily verify the precise type
-signatures of the required operations, but since type inference and default
-parameters are still applied in the provided block, it's also possible to encode
-usage protocols that doesn't reveal implementation details.
+The identifiers following the `generic` keyword represent instances of the
+currently matched type. These instances can act both as variables of the type,
+when used in contexts, where a value is expected, and as the type itself, when
+used in a contexts, where a type is expected.
+
+Please note that the ``is`` operator allows you to easily verify the precise
+type signatures of the required operations, but since type inference and
+default parameters are still applied in the provided block, it's also possible
+to encode usage protocols that doesn't reveal implementation details.
+
+As a special rule providing further convenience when writing type classes, any
+type value appearing in a callable expression will be treated as a variable of
+the designated type for overload resolution purposes, unless the type value was
+passed in its explicit ``typedesc[T]`` form:
+
+.. code-block:: nimrod
+  type
+    OutputStream = generic S
+      write(var S, string)
 
 Much like generics, the user defined type classes will be instantiated exactly
 once for each tested type and any static code included within them will also be
 executed once.
 
 
-
 Return Type Inference
 ---------------------
 
diff --git a/doc/tut1.txt b/doc/tut1.txt
index 0cc9b05c1..5c1cdb52e 100644
--- a/doc/tut1.txt
+++ b/doc/tut1.txt
@@ -610,7 +610,7 @@ allow to silently throw away a return value:
   discard yes("May I ask a pointless question?")
 
 
-The return value can be ignored implicitely if the called proc/iterator has
+The return value can be ignored implicitly if the called proc/iterator has
 been declared with the ``discardable`` pragma: 
 
 .. code-block:: nimrod
@@ -1077,7 +1077,7 @@ can also be used to include elements (and ranges of elements):
     TCharSet = set[char]
   var
     x: TCharSet
-  x = {'a'..'z', '0'..'9'} # This constructs a set that conains the
+  x = {'a'..'z', '0'..'9'} # This constructs a set that contains the
                            # letters from 'a' to 'z' and the digits
                            # from '0' to '9'
 
@@ -1201,7 +1201,7 @@ to specify a range from zero to the specified index minus one:
 Sequences
 ---------
 `Sequences`:idx: are similar to arrays but of dynamic length which may change
-during runtime (like strings). Since sequences are resizeable they are always
+during runtime (like strings). Since sequences are resizable they are always
 allocated on the heap and garbage collected.
 
 Sequences are always indexed with an ``int`` starting at position 0.
@@ -1547,7 +1547,7 @@ exported symbols. An alternative that only imports listed symbols is the
 
 Include statement
 -----------------
-The `include`:idx: statement does something fundametally different than
+The `include`:idx: statement does something fundamentally different than
 importing a module: it merely includes the contents of a file. The ``include``
 statement is useful to split up a large module into several files:
 
diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim
index 91664cd50..6dd407155 100644
--- a/lib/packages/docutils/rst.nim
+++ b/lib/packages/docutils/rst.nim
@@ -868,6 +868,12 @@ proc parseLine(p: var TRstParser, father: PRstNode) =
     case p.tok[p.idx].kind
     of tkWhite, tkWord, tkOther, tkPunct: parseInline(p, father)
     else: break 
+
+proc parseUntilNewline(p: var TRstParser, father: PRstNode) = 
+  while True: 
+    case p.tok[p.idx].kind
+    of tkWhite, tkWord, tkAdornment, tkOther, tkPunct: parseInline(p, father)
+    of tkEof, tkIndent: break
   
 proc parseSection(p: var TRstParser, result: PRstNode)
 proc parseField(p: var TRstParser): PRstNode = 
@@ -1078,7 +1084,7 @@ proc parseParagraph(p: var TRstParser, result: PRstNode) =
 
 proc parseHeadline(p: var TRstParser): PRstNode = 
   result = newRstNode(rnHeadline)
-  parseLine(p, result)
+  parseUntilNewLine(p, result)
   assert(p.tok[p.idx].kind == tkIndent)
   assert(p.tok[p.idx + 1].kind == tkAdornment)
   var c = p.tok[p.idx + 1].symbol[0]
@@ -1172,7 +1178,7 @@ proc parseOverline(p: var TRstParser): PRstNode =
   inc(p.idx, 2)
   result = newRstNode(rnOverline)
   while true: 
-    parseLine(p, result)
+    parseUntilNewline(p, result)
     if p.tok[p.idx].kind == tkIndent: 
       inc(p.idx)
       if p.tok[p.idx - 1].ival > currInd(p): 
diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim
index 043e713a6..901fdc779 100644
--- a/lib/pure/httpserver.nim
+++ b/lib/pure/httpserver.nim
@@ -401,8 +401,9 @@ proc nextAsync(s: PAsyncHTTPServer) =
       var value = ""
       i = header.parseUntil(key, ':')
       inc(i) # skip :
-      i += header.skipWhiteSpace(i)
-      i += header.parseUntil(value, {'\c', '\L'}, i)
+      if i < header.len:
+        i += header.skipWhiteSpace(i)
+        i += header.parseUntil(value, {'\c', '\L'}, i)
       s.headers[key] = value
     else:
       s.client.close()
diff --git a/lib/pure/irc.nim b/lib/pure/irc.nim
index 74ad7e26a..ee85d9c69 100644
--- a/lib/pure/irc.nim
+++ b/lib/pure/irc.nim
@@ -98,6 +98,7 @@ type
       params*: seq[string] ## Parameters of the IRC message
       origin*: string      ## The channel/user that this msg originated from
       raw*: string         ## Raw IRC message
+      timestamp*: TTime    ## UNIX epoch time the message was received
   
 proc send*(irc: PIRC, message: string, sendImmediately = false) =
   ## Sends ``message`` as a raw command. It adds ``\c\L`` for you.
@@ -160,9 +161,10 @@ proc isNumber(s: string): bool =
   result = i == s.len and s.len > 0
 
 proc parseMessage(msg: string): TIRCEvent =
-  result.typ = EvMsg
-  result.cmd = MUnknown
-  result.raw = msg
+  result.typ       = EvMsg
+  result.cmd       = MUnknown
+  result.raw       = msg
+  result.timestamp = times.getTime()
   var i = 0
   # Process the prefix
   if msg[i] == ':':
diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim
index 0fd1d8cd2..fbe0dda95 100644
--- a/lib/pure/oids.nim
+++ b/lib/pure/oids.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2012 Andreas Rumpf
+#        (c) Copyright 2013 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -52,6 +52,10 @@ proc oidToString*(oid: TOid, str: cstring) =
     inc(i)
   str[24] = '\0'
 
+proc `$`*(oid: TOid): string =
+  result = newString(25)
+  oidToString(oid, result)
+
 var
   incr: int 
   fuzz: int32
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim
index 99117ea4e..66bb1e6a9 100644
--- a/lib/pure/sockets.nim
+++ b/lib/pure/sockets.nim
@@ -154,9 +154,8 @@ proc newTSocket(fd: TSocketHandle, isBuff: bool): TSocket =
 proc `==`*(a, b: TPort): bool {.borrow.}
   ## ``==`` for ports.
 
-proc `$`*(p: TPort): string = 
+proc `$`*(p: TPort): string {.borrow.}
   ## returns the port number as a string
-  result = $ze(int16(p))
 
 proc ntohl*(x: int32): int32 = 
   ## Converts 32-bit integers from network to host byte order.
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 80a5ad8d3..e967ef683 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -246,7 +246,8 @@ proc toSeconds(a: TTimeInfo, interval: TTimeInterval): float =
     else:
       curMonth.inc()
   result += float(newinterv.days * 24 * 60 * 60)
-  result += float(newinterv.minutes * 60 * 60)
+  result += float(newinterv.hours * 60 * 60)
+  result += float(newinterv.minutes * 60)
   result += float(newinterv.seconds)
   result += newinterv.miliseconds / 1000
 
diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim
index 142178a86..4aacb2f71 100644
--- a/lib/pure/unicode.nim
+++ b/lib/pure/unicode.nim
@@ -55,31 +55,31 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
     result = TRune(ord(s[i]))
     when doInc: inc(i)
   elif ord(s[i]) shr 5 == 0b110:
-    assert(ord(s[i+1]) shr 6 == 0b10)
+    # assert(ord(s[i+1]) shr 6 == 0b10)
     result = TRune((ord(s[i]) and (ones(5))) shl 6 or 
                    (ord(s[i+1]) and ones(6)))
     when doInc: inc(i, 2)
   elif ord(s[i]) shr 4 == 0b1110:
-    assert(ord(s[i+1]) shr 6 == 0b10)
-    assert(ord(s[i+2]) shr 6 == 0b10)
+    # assert(ord(s[i+1]) shr 6 == 0b10)
+    # assert(ord(s[i+2]) shr 6 == 0b10)
     result = TRune((ord(s[i]) and ones(4)) shl 12 or
              (ord(s[i+1]) and ones(6)) shl 6 or
              (ord(s[i+2]) and ones(6)))
     when doInc: inc(i, 3)
   elif ord(s[i]) shr 3 == 0b11110:
-    assert(ord(s[i+1]) shr 6 == 0b10)
-    assert(ord(s[i+2]) shr 6 == 0b10)
-    assert(ord(s[i+3]) shr 6 == 0b10)
+    # assert(ord(s[i+1]) shr 6 == 0b10)
+    # assert(ord(s[i+2]) shr 6 == 0b10)
+    # assert(ord(s[i+3]) shr 6 == 0b10)
     result = TRune((ord(s[i]) and ones(3)) shl 18 or
              (ord(s[i+1]) and ones(6)) shl 12 or
              (ord(s[i+2]) and ones(6)) shl 6 or
              (ord(s[i+3]) and ones(6)))
     when doInc: inc(i, 4)
   elif ord(s[i]) shr 2 == 0b111110: 
-    assert(ord(s[i+1]) shr 6 == 0b10)
-    assert(ord(s[i+2]) shr 6 == 0b10)
-    assert(ord(s[i+3]) shr 6 == 0b10)
-    assert(ord(s[i+4]) shr 6 == 0b10)
+    # assert(ord(s[i+1]) shr 6 == 0b10)
+    # assert(ord(s[i+2]) shr 6 == 0b10)
+    # assert(ord(s[i+3]) shr 6 == 0b10)
+    # assert(ord(s[i+4]) shr 6 == 0b10)
     result = TRune((ord(s[i]) and ones(2)) shl 24 or
              (ord(s[i+1]) and ones(6)) shl 18 or
              (ord(s[i+2]) and ones(6)) shl 12 or
@@ -87,11 +87,11 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
              (ord(s[i+4]) and ones(6)))
     when doInc: inc(i, 5)
   elif ord(s[i]) shr 1 == 0b1111110: 
-    assert(ord(s[i+1]) shr 6 == 0b10)
-    assert(ord(s[i+2]) shr 6 == 0b10)
-    assert(ord(s[i+3]) shr 6 == 0b10)
-    assert(ord(s[i+4]) shr 6 == 0b10)
-    assert(ord(s[i+5]) shr 6 == 0b10)
+    # assert(ord(s[i+1]) shr 6 == 0b10)
+    # assert(ord(s[i+2]) shr 6 == 0b10)
+    # assert(ord(s[i+3]) shr 6 == 0b10)
+    # assert(ord(s[i+4]) shr 6 == 0b10)
+    # assert(ord(s[i+5]) shr 6 == 0b10)
     result = TRune((ord(s[i]) and ones(1)) shl 30 or
              (ord(s[i+1]) and ones(6)) shl 24 or
              (ord(s[i+2]) and ones(6)) shl 18 or
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
index 744c26d36..2bab79212 100644
--- a/lib/system/alloc.nim
+++ b/lib/system/alloc.nim
@@ -520,11 +520,18 @@ proc allocInv(a: TMemRegion): bool =
   for s in low(a.freeSmallChunks)..high(a.freeSmallChunks):
     var c = a.freeSmallChunks[s]
     while c != nil:
-      if c.next == c: return false
-      if c.size != s * MemAlign: return false
+      if c.next == c: 
+        echo "[SYSASSERT] c.next == c"
+        return false
+      if c.size != s * MemAlign: 
+        echo "[SYSASSERT] c.size != s * MemAlign"
+        return false
       var it = c.freeList
       while it != nil:
-        if it.zeroField != 0: return false
+        if it.zeroField != 0: 
+          echo "[SYSASSERT] it.zeroField != 0"
+          cprintf("%ld %p\n", it.zeroField, it)
+          return false
         it = it.next
       c = c.next
   result = true
@@ -591,6 +598,7 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
     add(a, a.root, cast[TAddress](result), cast[TAddress](result)+%size)
   sysAssert(isAccessible(a, result), "rawAlloc 14")
   sysAssert(allocInv(a), "rawAlloc: end")
+  when logAlloc: cprintf("rawAlloc: %ld %p\n", requestedSize, result)
 
 proc rawAlloc0(a: var TMemRegion, requestedSize: int): pointer =
   result = rawAlloc(a, requestedSize)
@@ -638,6 +646,7 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
     del(a, a.root, cast[int](addr(c.data)))
     freeBigChunk(a, c)
   sysAssert(allocInv(a), "rawDealloc: end")
+  when logAlloc: cprintf("rawDealloc: %p\n", p)
 
 proc isAllocatedPtr(a: TMemRegion, p: pointer): bool = 
   if isAccessible(a, p):
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index c5d4d2aa2..48705db96 100644
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -9,7 +9,7 @@
 
 #            Garbage Collector
 #
-# The basic algorithm is *Deferrent Reference Counting* with cycle detection.
+# The basic algorithm is *Deferred Reference Counting* with cycle detection.
 # This is achieved by combining a Deutsch-Bobrow garbage collector
 # together with Christoper's partial mark-sweep garbage collector.
 #
@@ -407,12 +407,17 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
         return
     add(gch.zct, res)
 
+{.push stackTrace: off, profiler:off.}
+proc gcInvariant*(msg: string) =
+  sysAssert(allocInv(gch.region), msg)
+{.pop.}
+
 proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
   # generates a new object and sets its reference counter to 0
+  sysAssert(allocInv(gch.region), "rawNewObj begin")
   acquire(gch)
   gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
   collectCT(gch)
-  sysAssert(allocInv(gch.region), "rawNewObj begin")
   var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
   gcAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
   # now it is buffered in the ZCT
@@ -517,7 +522,9 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
     writeCell("growObj new cell", res)
   gcTrace(ol, csZctFreed)
   gcTrace(res, csAllocated)
-  when reallyDealloc: rawDealloc(gch.region, ol)
+  when reallyDealloc: 
+    sysAssert(allocInv(gch.region), "growObj before dealloc")
+    rawDealloc(gch.region, ol)
   else:
     sysAssert(ol.typ != nil, "growObj: 5")
     zeroMem(ol, sizeof(TCell))
@@ -537,7 +544,9 @@ proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
   prepareDealloc(c)
   gcTrace(c, csCycFreed)
   when logGC: writeCell("cycle collector dealloc cell", c)
-  when reallyDealloc: rawDealloc(gch.region, c)
+  when reallyDealloc: 
+    sysAssert(allocInv(gch.region), "free cyclic cell")
+    rawDealloc(gch.region, c)
   else:
     gcAssert(c.typ != nil, "freeCyclicCell")
     zeroMem(c, sizeof(TCell))
@@ -910,7 +919,9 @@ proc collectZCT(gch: var TGcHeap): bool =
       # access invalid memory. This is done by prepareDealloc():
       prepareDealloc(c)
       forAllChildren(c, waZctDecRef)
-      when reallyDealloc: rawDealloc(gch.region, c)
+      when reallyDealloc: 
+        sysAssert(allocInv(gch.region), "collectZCT: rawDealloc")
+        rawDealloc(gch.region, c)
       else:
         sysAssert(c.typ != nil, "collectZCT 2")
         zeroMem(c, sizeof(TCell))
diff --git a/lib/system/gc2.nim b/lib/system/gc2.nim
index 05c291371..31c99a601 100644
--- a/lib/system/gc2.nim
+++ b/lib/system/gc2.nim
@@ -387,8 +387,7 @@ template `--`(rc: TRefCount): expr =
   rc <% rcIncrement
 
 template `--` (rc: TRefCount, heapType: THeapType): expr =
-  (when heapType == SharedHeap: atomicDec(rc, rcIncrement) <% rcIncrement
-   else: --rc)
+  (when heapType == SharedHeap: atomicDec(rc, rcIncrement) <% rcIncrement else: --rc)
 
 template doDecRef(cc: PCell,
                   heapType = LocalHeap,
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index c9801abad..118272ee3 100644
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -28,6 +28,7 @@ const
   reallyOsDealloc = true
   coalescRight = true
   coalescLeft = true
+  logAlloc = false
 
 type
   PPointer = ptr pointer
diff --git a/tests/run/tstaticparams.nim b/tests/run/tstaticparams.nim
index 232748356..f2d6e1dd6 100644
--- a/tests/run/tstaticparams.nim
+++ b/tests/run/tstaticparams.nim
@@ -10,6 +10,10 @@ type
   TBar[T; I: expr[int]] = object
     data: array[I, T]
 
+  TA1[T; I: expr[int]] = array[I, T]
+  TA2[T; I: expr[int]] = array[0..I, T]
+  TA3[T; I: expr[int]] = array[I-1, T]
+
 proc takeFoo(x: TFoo) =
   echo "abracadabra"
   echo TFoo.Val
@@ -20,3 +24,8 @@ takeFoo(x)
 var y: TBar[float, 4]
 echo high(y.data)
 
+var
+  t1: TA1
+  t2: TA2
+  t3: TA3
+
diff --git a/tests/run/tusertypeclasses.nim b/tests/run/tusertypeclasses.nim
new file mode 100644
index 000000000..4c2f07b85
--- /dev/null
+++ b/tests/run/tusertypeclasses.nim
@@ -0,0 +1,28 @@
+discard """
+  output: "Sortable\nSortable\nContainer"
+"""
+
+import typetraits
+
+type
+  TObj = object
+    x: int
+
+  Sortable = generic x, y
+    (x < y) is bool
+
+  ObjectContainer = generic C
+    C.len is ordinal
+    for v in items(C):
+      v.type is tuple|object
+
+proc foo(c: ObjectContainer) =
+  echo "Container"
+
+proc foo(x: Sortable) =
+  echo "Sortable"
+
+foo 10
+foo "test"
+foo(@[TObj(x: 10), TObj(x: 20)])
+