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/nimconf.nim5
-rw-r--r--compiler/nimrod.nimrod.cfg (renamed from compiler/nimrod.cfg)0
-rw-r--r--compiler/parser.nim15
-rw-r--r--compiler/sem.nim53
-rw-r--r--compiler/semdata.nim4
-rw-r--r--compiler/semexprs.nim44
-rw-r--r--compiler/semstmts.nim41
-rw-r--r--compiler/semtypes.nim3
-rw-r--r--compiler/sigmatch.nim68
-rw-r--r--doc/lib.txt2
-rw-r--r--doc/manual.txt31
-rw-r--r--doc/tut1.txt54
-rw-r--r--lib/core/macros.nim2
-rw-r--r--lib/packages/docutils/rst.nim10
-rw-r--r--lib/pure/fsmonitor.nim10
-rw-r--r--lib/pure/htmlparser.nim30
-rw-r--r--lib/pure/httpserver.nim5
-rw-r--r--lib/pure/irc.nim8
-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.nim53
-rw-r--r--lib/system/channels.nim3
-rw-r--r--lib/system/gc2.nim3
-rw-r--r--lib/system/threads.nim3
-rw-r--r--readme.md10
-rw-r--r--readme.txt10
-rw-r--r--tests/compile/tgeneric.nim8
-rw-r--r--tests/run/tdrdobbs_examples.nim134
-rw-r--r--tests/run/tusertypeclasses.nim28
-rw-r--r--tests/run/tvarious1.nim14
34 files changed, 559 insertions, 187 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/nimconf.nim b/compiler/nimconf.nim
index 507812d9c..7ec566a01 100644
--- a/compiler/nimconf.nim
+++ b/compiler/nimconf.nim
@@ -243,11 +243,6 @@ proc LoadConfigs*(cfg: string) =
     readConfigFile(pd / cfg)
     
     if gProjectName.len != 0:
-      var conffile = changeFileExt(gProjectFull, "cfg")
-      if conffile != pd / cfg and existsFile(conffile):
-        readConfigFile(conffile)
-        rawMessage(warnConfigDeprecated, conffile)
-      
       # new project wide config file:
       readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg"))
  
diff --git a/compiler/nimrod.cfg b/compiler/nimrod.nimrod.cfg
index ac8f732f1..ac8f732f1 100644
--- a/compiler/nimrod.cfg
+++ b/compiler/nimrod.nimrod.cfg
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..3ace623bc 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
@@ -89,6 +90,24 @@ proc commonType*(x, y: PType): PType =
     let idx = ord(b.kind in {tyArray, tyArrayConstr})
     if a.sons[idx].kind == tyEmpty: return y
     #elif b.sons[idx].kind == tyEmpty: return x
+  elif a.kind == tyRange and b.kind == tyRange:
+    # consider:  (range[0..3], range[0..4]) here. We should make that
+    # range[0..4]. But then why is (range[0..4], 6) not range[0..6]?
+    # But then why is (2,4) not range[2..4]? But I think this would break
+    # too much code. So ... it's the same range or the base type. This means
+    #  type(if b: 0 else 1) == int and not range[0..1]. For now. In the long
+    # run people expect ranges to work properly within a tuple.
+    if not sameType(a, b):
+      result = skipTypes(a, {tyRange}).skipIntLit
+    when false:
+      if a.kind != tyRange and b.kind == tyRange:
+        # XXX This really needs a better solution, but a proper fix now breaks
+        # code.
+        result = a #.skipIntLit
+      elif a.kind == tyRange and b.kind != tyRange:
+        result = b #.skipIntLit
+      elif a.kind in IntegralTypes and a.n != nil:
+        result = a #.skipIntLit
   else:
     var k = tyNone
     if a.kind in {tyRef, tyPtr}:
@@ -102,7 +121,7 @@ proc commonType*(x, y: PType): PType =
       if result.isNil: return x
       if k != tyNone:
         let r = result
-        result = NewType(k, r.owner)
+        result = newType(k, r.owner)
         result.addSonSkipIntLit(r)
 
 proc isTopLevel(c: PContext): bool {.inline.} = 
@@ -139,26 +158,27 @@ 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
+when false:
+  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 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 = tryExpr(c, n)
+    if result == nil:
+      result = newSymNode(errorSym(c, n))
+    elif result.typ == nil:
       result = newSymNode(getSysSym"void")
     else:
-      result = symNodeFromType(c, e.typ, n.info)
+      result.typ = makeTypeDesc(c, result.typ)
 
   result.handleIsOperator = proc (n: PNode): PNode =
     result = IsOpImpl(c, n)
@@ -209,7 +229,8 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
     of tyTypeDesc:
       if n.kind == nkStmtList: result.kind = nkStmtListType
       var typ = semTypeNode(c, result, nil)
-      result = symNodeFromType(c, typ, n.info)
+      result.typ = makeTypeDesc(c, typ)
+      #result = symNodeFromType(c, typ, n.info)
     else:
       result = semExpr(c, result)
       result = fitNode(c, s.typ.sons[0], result)
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..775d4e7a0 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -191,7 +191,7 @@ proc isCastable(dst, src: PType): bool =
 proc isSymChoice(n: PNode): bool {.inline.} =
   result = n.kind in nkSymChoices
 
-proc semConv(c: PContext, n: PNode, s: PSym): PNode =
+proc semConv(c: PContext, n: PNode): PNode =
   if sonsLen(n) != 2:
     LocalError(n.info, errConvNeedsOneArg)
     return n
@@ -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}
@@ -729,8 +738,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
   elif t != nil and t.kind == tyTypeDesc:
     if n.len == 1: return semObjConstr(c, n, flags)
     let destType = t.skipTypes({tyTypeDesc, tyGenericInst})
-    result = semConv(c, n, symFromType(destType, n.info))
-    return
+    return semConv(c, n)
   else:
     result = overloadedCallOpr(c, n)
     # Now that nkSym does not imply an iteration over the proc/iterator space,
@@ -763,7 +771,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 +823,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
@@ -1038,7 +1047,9 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
     # The result so far is a tyTypeDesc bound 
     # a tyGenericBody. The line below will substitute
     # it with the instantiated type.
-    result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
+    result = n
+    result.typ = makeTypeDesc(c, semTypeNode(c, n, nil))
+    #result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
   of tyTuple: 
     checkSonsLen(n, 2)
     n.sons[0] = makeDeref(n.sons[0])
@@ -1208,7 +1219,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 +1440,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 +1454,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 +1478,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
 
@@ -1871,7 +1884,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     result = semExpr(c, n.sons[0], flags)
   of nkTypeOfExpr, nkTupleTy, nkRefTy..nkEnumTy:
     var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
-    result = symNodeFromType(c, typ, n.info)
+    result.typ = makeTypeDesc(c, typ)
+    #result = symNodeFromType(c, typ, n.info)
   of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: 
     # check if it is an expression macro:
     checkMinSonsLen(n, 1)
@@ -1894,7 +1908,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
       of skType:
         # XXX think about this more (``set`` procs)
         if n.len == 2:
-          result = semConv(c, n, s)
+          result = semConv(c, n)
         elif n.len == 1:
           result = semObjConstr(c, n, flags)
         elif Contains(c.AmbiguousSymbols, s.id): 
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index ed6787a16..a1805fdec 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)
@@ -1082,6 +1087,8 @@ proc semIterator(c: PContext, n: PNode): PNode =
   # -- at least for 0.9.2.
   if s.typ.callConv == ccClosure:
     incl(s.typ.flags, tfCapturesEnv)
+  else:
+    s.typ.callConv = ccInline
   when false:
     if s.typ.callConv != ccInline: 
       s.typ.callConv = ccClosure
@@ -1104,24 +1111,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 +1136,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 +1228,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/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 5c1cdb52e..2070c69d6 100644
--- a/doc/tut1.txt
+++ b/doc/tut1.txt
@@ -189,9 +189,18 @@ to a storage location:
   var x = "abc" # introduces a new variable `x` and assigns a value to it
   x = "xyz"     # assigns a new value to `x`
 
-``=`` is the *assignment operator*. The assignment operator cannot
-be overloaded, overwritten or forbidden, but this might change in a future
-version of Nimrod.
+``=`` is the *assignment operator*. The assignment operator cannot be
+overloaded, overwritten or forbidden, but this might change in a future version
+of Nimrod. You can declare multiple variables with a single assignment
+statement and all the variables will have the same value:
+
+.. code-block::
+  var x, y = 3  # assigns 3 to the variables `x` and `y`
+  echo "x ", x  # outputs "x 3"
+  echo "y ", y  # outputs "y 3"
+  x = 42        # changes `x` to 42 without changing `y`
+  echo "x ", x  # outputs "x 42"
+  echo "y ", y  # outputs "y 3"
 
 
 Constants
@@ -1352,6 +1361,45 @@ Even though you don't need to declare a type for a tuple to use it, tuples
 created with different field names will be considered different objects despite
 having the same field types.
 
+Tuples can be *unpacked* during variable assignment (and only then!). This can
+be handy to assign directly the fields of the tuples to individually named
+variables. An example of this is the ``splitFile`` proc from the `os module
+<os.html>`_ which returns the directory, name and extension of a path at the
+same time. For tuple unpacking to work you have to use parenthesis around the
+values you want to assign the unpacking to, otherwise you will be assigning the
+same value to all the individual variables! Example:
+
+.. code-block:: nimrod
+
+  import os
+
+  let
+    path = "usr/local/nimrodc.html"
+    (dir, name, ext) = splitFile(path)
+    baddir, badname, badext = splitFile(path)
+  echo dir      # outputs `usr/local`
+  echo name     # outputs `nimrodc`
+  echo ext      # outputs `.html`
+  # All the following output the same line:
+  # `(dir: usr/local, name: nimrodc, ext: .html)`
+  echo baddir
+  echo badname
+  echo badext
+
+Tuple unpacking **only** works in ``var`` or ``let`` blocks. The following code
+won't compile:
+
+.. code-block:: nimrod
+
+  import os
+
+  var
+    path = "usr/local/nimrodc.html"
+    dir, name, ext = ""
+
+  (dir, name, ext) = splitFile(path)
+  # --> Error: '(dir, name, ext)' cannot be assigned to
+
 
 Reference and pointer types
 ---------------------------
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index fc93a157d..d01d4ebee 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -494,7 +494,7 @@ const
 
 from strutils import cmpIgnoreStyle, format
 
-proc ExpectKind*(n: PNimrodNode; k: set[TNimrodNodeKind]) {.compileTime.} =
+proc expectKind*(n: PNimrodNode; k: set[TNimrodNodeKind]) {.compileTime.} =
   assert n.kind in k, "Expected one of $1, got $2".format(k, n.kind)
 
 proc newProc*(name = newEmptyNode(); params: openarray[PNimrodNode] = [];  
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/fsmonitor.nim b/lib/pure/fsmonitor.nim
index a554cf963..d6584c1a0 100644
--- a/lib/pure/fsmonitor.nim
+++ b/lib/pure/fsmonitor.nim
@@ -64,10 +64,10 @@ const
 proc newMonitor*(): PFSMonitor =
   ## Creates a new file system monitor.
   new(result)
-  result.fd = inotifyInit()
   result.targets = initTable[cint, string]()
+  result.fd = inotifyInit()
   if result.fd < 0:
-    OSError()
+    OSError(OSLastError())
 
 proc add*(monitor: PFSMonitor, target: string,
                filters = {MonitorAll}): cint {.discardable.} =
@@ -93,7 +93,7 @@ proc add*(monitor: PFSMonitor, target: string,
   
   result = inotifyAddWatch(monitor.fd, target, INFilter.uint32)
   if result < 0:
-    OSError()
+    OSError(OSLastError())
   monitor.targets.add(result, target)
 
 proc del*(monitor: PFSMonitor, wd: cint) =
@@ -101,7 +101,7 @@ proc del*(monitor: PFSMonitor, wd: cint) =
   ##
   ## If ``wd`` is not a part of ``monitor`` an EOS error is raised.
   if inotifyRmWatch(monitor.fd, wd) < 0:
-    OSError()
+    OSError(OSLastError())
 
 proc getEvent(m: PFSMonitor, fd: cint): seq[TMonitorEvent] =
   result = @[]
@@ -184,7 +184,7 @@ proc FSMonitorRead(h: PObject) =
 proc toDelegate(m: PFSMonitor): PDelegate =
   result = newDelegate()
   result.deleVal = m
-  result.fd = m.fd
+  result.fd = (type(result.fd))(m.fd)
   result.mode = fmRead
   result.handleRead = FSMonitorRead
   result.open = true
diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim
index d60d2e583..060f0e386 100644
--- a/lib/pure/htmlparser.nim
+++ b/lib/pure/htmlparser.nim
@@ -17,11 +17,37 @@
 ##
 ##   echo loadHtml("mydirty.html")
 ##
-##
 ## Every tag in the resulting tree is in lower case.
 ##
 ## **Note:** The resulting ``PXmlNode`` already uses the ``clientData`` field, 
 ## so it cannot be used by clients of this library.
+##
+## Example: Transforming hyperlinks
+## ================================
+##
+## This code demonstrates how you can iterate over all the tags in an HTML file
+## and write back the modified version. In this case we look for hyperlinks
+## ending with the extension ``.rst`` and convert them to ``.html``.
+##
+## .. code-block:: nimrod
+##
+##   import htmlparser
+##   import xmltree  # To use '$' for PXmlNode
+##   import strtabs  # To access PXmlAttributes
+##   import os       # To use splitFile
+##   import strutils # To use cmpIgnoreCase
+##
+##   proc transformHyperlinks() =
+##     let html = loadHTML("input.html")
+##
+##     for a in html.findAll("a"):
+##       let href = a.attrs["href"]
+##       if not href.isNil:
+##         let (dir, filename, ext) = splitFile(href)
+##         if cmpIgnoreCase(ext, ".rst") == 0:
+##           a.attrs["href"] = dir / filename & ".html"
+##
+##     writeFile("output.html", $html)
 
 import strutils, streams, parsexml, xmltree, unicode, strtabs
 
@@ -528,7 +554,7 @@ proc parseHtml*(s: PStream, filename: string,
   ## parses the XML from stream `s` and returns a ``PXmlNode``. Every
   ## occured parsing error is added to the `errors` sequence.
   var x: TXmlParser
-  open(x, s, filename, {reportComments})
+  open(x, s, filename, {reportComments, reportWhitespace})
   next(x)
   # skip the DOCTYPE:
   if x.kind == xmlSpecial: next(x)
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/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.nim b/lib/system.nim
index b2d19a885..dc5a406d1 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -374,10 +374,10 @@ proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
   ## This is equivalent to ``s = @[]; setlen(s, len)``, but more
   ## efficient since no reallocation is needed.
   ##
-  ## Note that the sequence will be filled with uninitialized entries, which
-  ## can be a problem for sequences containing strings. After the creation of
-  ## the sequence you should assign entries to the sequence instead of adding
-  ## them. Example:
+  ## Note that the sequence will be filled with zeroed entries, which can be a
+  ## problem for sequences containing strings since their value will be
+  ## ``nil``. After the creation of the sequence you should assign entries to
+  ## the sequence instead of adding them. Example:
   ##
   ## .. code-block:: nimrod
   ##   var inputStrings : seq[string]
@@ -390,10 +390,10 @@ proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
 proc newSeq*[T](len = 0): seq[T] =
   ## creates a new sequence of type ``seq[T]`` with length ``len``.
   ##
-  ## Note that the sequence will be filled with uninitialized entries, which
-  ## can be a problem for sequences containing strings. After the creation of
-  ## the sequence you should assign entries to the sequence instead of adding
-  ## them. Example:
+  ## Note that the sequence will be filled with zeroed entries, which can be a
+  ## problem for sequences containing strings since their value will be
+  ## ``nil``. After the creation of the sequence you should assign entries to
+  ## the sequence instead of adding them. Example:
   ##
   ## .. code-block:: nimrod
   ##   var inputStrings = newSeq[string](3)
@@ -999,11 +999,17 @@ type
     ## platform-dependant in general.
 
 when defined(windows):
-  type clong* {.importc: "long", nodecl.} = int32
-    ## This is the same as the type ``long`` in *C*.
+  type
+    clong* {.importc: "long", nodecl.} = int32
+      ## This is the same as the type ``long`` in *C*.
+    culong* {.importc: "unsigned long", nodecl.} = uint32
+      ## This is the same as the type ``unsigned long`` in *C*.
 else:
-  type clong* {.importc: "long", nodecl.} = int
-    ## This is the same as the type ``long`` in *C*.
+  type
+    clong* {.importc: "long", nodecl.} = int
+      ## This is the same as the type ``long`` in *C*.
+    culong* {.importc: "unsigned long", nodecl.} = uint
+      ## This is the same as the type ``unsigned long`` in *C*.
 
 type # these work for most platforms:
   cchar* {.importc: "char", nodecl.} = char
@@ -1032,8 +1038,6 @@ type # these work for most platforms:
     ## This is the same as the type ``unsigned short`` in *C*.
   cuint* {.importc: "int", nodecl.} = uint32
     ## This is the same as the type ``unsigned int`` in *C*.
-  culong* {.importc: "unsigned long", nodecl.} = uint
-    ## This is the same as the type ``unsigned long`` in *C*.
   culonglong* {.importc: "unsigned long long", nodecl.} = uint64
     ## This is the same as the type ``unsigned long long`` in *C*.
 
@@ -1042,10 +1046,10 @@ type # these work for most platforms:
     ## high value is large enough to disable bounds checking in practice.
     ## Use `cstringArrayToSeq` to convert it into a ``seq[string]``.
   
-  PFloat32* = ptr Float32 ## an alias for ``ptr float32``
-  PFloat64* = ptr Float64 ## an alias for ``ptr float64``
-  PInt64* = ptr Int64 ## an alias for ``ptr int64``
-  PInt32* = ptr Int32 ## an alias for ``ptr int32``
+  PFloat32* = ptr float32 ## an alias for ``ptr float32``
+  PFloat64* = ptr float64 ## an alias for ``ptr float64``
+  PInt64* = ptr int64 ## an alias for ``ptr int64``
+  PInt32* = ptr int32 ## an alias for ``ptr int32``
 
 proc toFloat*(i: int): float {.
   magic: "ToFloat", noSideEffect, importc: "toFloat".}
@@ -2615,12 +2619,13 @@ type
   PNimrodNode* {.magic: "PNimrodNode".} = ref TNimrodNode
     ## represents a Nimrod AST node. Macros operate on this type.
 
-template eval*(blk: stmt): stmt =
-  ## executes a block of code at compile time just as if it was a macro
-  ## optionally, the block can return an AST tree that will replace the 
-  ## eval expression
-  macro payload: stmt {.gensym.} = blk
-  payload()
+when false:
+  template eval*(blk: stmt): stmt =
+    ## executes a block of code at compile time just as if it was a macro
+    ## optionally, the block can return an AST tree that will replace the 
+    ## eval expression
+    macro payload: stmt {.gensym.} = blk
+    payload()
 
 when hostOS != "standalone":
   proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} = 
diff --git a/lib/system/channels.nim b/lib/system/channels.nim
index d0294322a..9c3cc93e0 100644
--- a/lib/system/channels.nim
+++ b/lib/system/channels.nim
@@ -13,6 +13,9 @@
 ##

 ## **Note:** The current implementation of message passing is slow and does

 ## not work with cyclic data structures.

+  
+when not defined(NimString): 
+  {.error: "You must not import this module explicitly".}
 

 type

   pbytes = ptr array[0.. 0xffff, byte]

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/threads.nim b/lib/system/threads.nim
index 7d74de92d..104ca63c1 100644
--- a/lib/system/threads.nim
+++ b/lib/system/threads.nim
@@ -39,6 +39,9 @@
 ##    createThread(thr[i], threadFunc, (i*10, i*10+5))
 ##  joinThreads(thr)
   
+when not defined(NimString): 
+  {.error: "You must not import this module explicitly".}
+
 const
   maxRegisters = 256 # don't think there is an arch with more registers
   useStackMaskHack = false ## use the stack mask hack for better performance
diff --git a/readme.md b/readme.md
index f74f81283..8d42c66db 100644
--- a/readme.md
+++ b/readme.md
@@ -9,7 +9,7 @@ the C source of an older version of the compiler are needed to bootstrap the
 latest version. The C sources are available in a separate repo [here](http://github.com/nimrod-code/csources).
 
 Pre-compiled snapshots of the compiler are also available on
-[Nimbuild](http://build.nimrod-code.org/). Your platform however may not 
+[Nimbuild](http://build.nimrod-lang.org/). Your platform however may not 
 currently be built for.
 
 The compiler currently supports the following platform and architecture 
@@ -47,9 +47,11 @@ The above steps can be performed on Windows in a similar fashion, the
 instead of ``build.sh``.
 
 ## Getting help
-A [forum](http://forum.nimrod-code.org/) is available if you have any questions,
-and you can also get help in the IRC channel
-on [Freenode](irc://irc.freenode.net/nimrod) in #nimrod.
+A [forum](http://forum.nimrod-lang.org/) is available if you have any
+questions, and you can also get help in the IRC channel on
+[Freenode](irc://irc.freenode.net/nimrod) in #nimrod. If you ask questions on
+[StackOverflow use the nimrod
+tag](http://stackoverflow.com/questions/tagged/nimrod).
 
 ## License
 The compiler and the standard library are licensed under the MIT license, 
diff --git a/readme.txt b/readme.txt
index f74f81283..8d42c66db 100644
--- a/readme.txt
+++ b/readme.txt
@@ -9,7 +9,7 @@ the C source of an older version of the compiler are needed to bootstrap the
 latest version. The C sources are available in a separate repo [here](http://github.com/nimrod-code/csources).
 
 Pre-compiled snapshots of the compiler are also available on
-[Nimbuild](http://build.nimrod-code.org/). Your platform however may not 
+[Nimbuild](http://build.nimrod-lang.org/). Your platform however may not 
 currently be built for.
 
 The compiler currently supports the following platform and architecture 
@@ -47,9 +47,11 @@ The above steps can be performed on Windows in a similar fashion, the
 instead of ``build.sh``.
 
 ## Getting help
-A [forum](http://forum.nimrod-code.org/) is available if you have any questions,
-and you can also get help in the IRC channel
-on [Freenode](irc://irc.freenode.net/nimrod) in #nimrod.
+A [forum](http://forum.nimrod-lang.org/) is available if you have any
+questions, and you can also get help in the IRC channel on
+[Freenode](irc://irc.freenode.net/nimrod) in #nimrod. If you ask questions on
+[StackOverflow use the nimrod
+tag](http://stackoverflow.com/questions/tagged/nimrod).
 
 ## License
 The compiler and the standard library are licensed under the MIT license, 
diff --git a/tests/compile/tgeneric.nim b/tests/compile/tgeneric.nim
index 8bda15c42..9292b729f 100644
--- a/tests/compile/tgeneric.nim
+++ b/tests/compile/tgeneric.nim
@@ -8,4 +8,12 @@ proc foo(models: seq[TTable[string, float]]): seq[float] =
   for model in models.items:
     result.add model["foobar"]
 
+# bug #686
+type TType[T; A] = array[A, T]
+
+proc foo[T](p: TType[T, range[0..1]]) =
+  echo "foo"
+proc foo[T](p: TType[T, range[0..2]]) =
+  echo "bar"
+
 
diff --git a/tests/run/tdrdobbs_examples.nim b/tests/run/tdrdobbs_examples.nim
new file mode 100644
index 000000000..d1e0585d2
--- /dev/null
+++ b/tests/run/tdrdobbs_examples.nim
@@ -0,0 +1,134 @@
+discard """
+  output: '''108
+11 -1 1936
+4.000000000000002-e001
+true
+truefalse'''
+"""
+
+proc `++`(x: var int; y: int = 1; z: int = 0) =
+  x = x + y + z
+
+var g = 70
+++g
+g ++ 7
+g.`++`(10, 20)
+echo g 
+
+
+#let lv = stdin.readline
+#var vv = stdin.readline
+#vv = "abc" # valid, reassignment allowed
+#lv = "abc" # fails at compile time
+
+#proc square(x: int): int = x*x
+
+template square(x: int): int =
+  # ensure 'x' is only evaluated once:
+  let y = x
+  y * y
+
+proc mostSignificantBit(n: int): int =
+  # naive algorithm:
+  var n = n
+  while n != 0:
+    n = n shr 1
+    result += 1
+  result -= 1
+
+const msb3999 = mostSignificantBit(3999)
+
+echo msb3999, " ", mostSignificantBit(0), " ", square(44)
+
+proc filter[T](a: openarray[T], predicate: proc (x: T): bool): seq[T] =
+  result = @[] # @[] constructs the empty seq
+  for x in a:
+    if predicate(x): result.add(x)
+
+proc map[T, S](a: openarray[T], fn: proc (x: T): S): seq[S] =
+  newSeq(result, a.len)
+  for i in 0 .. <a.len: result[i] = fn(a[i])
+
+
+type
+  FormulaKind = enum
+    fkVar,        ## element is a variable like 'X'
+    fkLit,        ## element is a literal like 0.1
+    fkAdd,        ## element is an addition operation
+    fkMul,        ## element is a multiplication operation
+    fkExp         ## element is an exponentiation operation 
+
+type
+  Formula = ref object
+    case kind: FormulaKind
+    of fkVar: name: string
+    of fkLit: value: float
+    of fkAdd, fkMul, fkExp: left, right: Formula
+
+from math import pow
+
+proc evaluate(n: Formula, varToVal: proc (name: string): float): float =
+  case n.kind
+  of fkVar: varToVal(n.name)
+  of fkLit: n.value
+  of fkAdd: evaluate(n.left, varToVal) + evaluate(n.right, varToVal)
+  of fkMul: evaluate(n.left, varToVal) * evaluate(n.right, varToVal)
+  of fkExp: pow(evaluate(n.left, varToVal), evaluate(n.right, varToVal))
+
+echo evaluate(Formula(kind: fkLit, value: 0.4), nil)
+
+proc isPolyTerm(n: Formula): bool =
+  n.kind == fkMul and n.left.kind == fkLit and (let e = n.right; 
+    e.kind == fkExp and e.left.kind == fkVar and e.right.kind == fkLit)
+
+proc isPolynomial(n: Formula): bool =
+  isPolyTerm(n) or 
+    (n.kind == fkAdd and isPolynomial(n.left) and isPolynomial(n.right))
+
+let myFormula = Formula(kind: fkMul,
+                        left: Formula(kind: fkLit, value: 2.0),
+                        right: Formula(kind: fkExp, 
+                          left: Formula(kind: fkVar, name: "x"),
+                          right: Formula(kind: fkLit, value: 5.0)))
+
+echo isPolyTerm(myFormula)
+
+proc pat2kind(pattern: string): FormulaKind =
+  case pattern
+  of "^": fkExp
+  of "*": fkMul
+  of "+": fkAdd
+  of "x": fkVar
+  of "c": fkLit
+  else:   fkVar # no error reporting for reasons of simplicity
+
+import macros
+
+proc matchAgainst(n, pattern: PNimrodNode): PNimrodNode {.compileTime.} =
+  template `@`(current, field: expr): expr =
+    newDotExpr(current, newIdentNode(astToStr(field)))
+
+  template `==@`(n, pattern: expr): expr =
+    newCall("==", n@kind, newIdentNode($pat2kind($pattern.ident)))
+
+  case pattern.kind
+  of CallNodes:
+    result = newCall("and",
+      n ==@ pattern[0],
+      matchAgainst(n@left, pattern[1]))
+    if pattern.len == 3:
+      result = newCall("and", result.copy,
+        matchAgainst(n@right, pattern[2]))
+  of nnkIdent:
+    result = n ==@ pattern
+  of nnkPar:
+    result = matchAgainst(n, pattern[0])
+  else:
+    error "invalid pattern"
+
+macro `=~` (n: Formula, pattern: expr): bool =
+  result = matchAgainst(n, pattern)
+
+proc isPolyTerm2(n: Formula): bool = n =~ c * x^c
+
+echo isPolyTerm2(myFormula), isPolyTerm2(Formula(kind: fkLit, value: 0.7))
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)])
+
diff --git a/tests/run/tvarious1.nim b/tests/run/tvarious1.nim
index 9dd4af606..6e4612ae3 100644
--- a/tests/run/tvarious1.nim
+++ b/tests/run/tvarious1.nim
@@ -2,7 +2,8 @@ discard """
   file: "tlenopenarray.nim"
   output: '''1
 0
-Whopie'''
+Whopie
+12'''
 """
 
 echo len([1_000_000]) #OUT 1
@@ -27,3 +28,14 @@ var w = TWidget(names: initQueue[string]())
 add(w.names, "Whopie")
 
 for n in w.names: echo(n)
+
+# bug #681
+
+type TSomeRange = object
+  hour: range[0..23]
+
+var value: string
+var val12 = TSomeRange(hour: 12)
+
+value = $(if val12.hour > 12: val12.hour - 12 else: val12.hour)
+echo value