summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ccgcalls.nim15
-rw-r--r--compiler/ccgexprs.nim23
-rw-r--r--compiler/ccgtypes.nim114
-rw-r--r--compiler/ccgutils.nim6
-rw-r--r--compiler/cgen.nim4
-rw-r--r--compiler/msgs.nim7
-rw-r--r--compiler/sem.nim10
-rw-r--r--compiler/semexprs.nim6
-rw-r--r--compiler/semstmts.nim13
-rw-r--r--compiler/types.nim101
-rw-r--r--koch.nim6
-rw-r--r--lib/pure/httpclient.nim49
-rw-r--r--lib/pure/selectors.nim2
-rw-r--r--lib/pure/terminal.nim8
-rw-r--r--lib/system.nim2
-rw-r--r--lib/system/excpt.nim2
-rw-r--r--tests/generics/tgeneric_inheritance.nim2
-rw-r--r--tests/generics/tmetafield.nim2
-rw-r--r--web/community.txt10
19 files changed, 225 insertions, 157 deletions
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 4f7856769..cb8dcc25b 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -302,10 +302,11 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope =
   while i < pat.len:
     case pat[i]
     of '@':
-      result.app genOtherArg(p, ri, j, typ)
-      for k in j+1 .. < ri.len:
-        result.app(~", ")
-        result.app genOtherArg(p, ri, k, typ)
+      if j < ri.len:
+        result.app genOtherArg(p, ri, j, typ)
+        for k in j+1 .. < ri.len:
+          result.app(~", ")
+          result.app genOtherArg(p, ri, k, typ)
       inc i
     of '#':
       if pat[i+1] in {'+', '@'}:
@@ -448,8 +449,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
 proc genCall(p: BProc, e: PNode, d: var TLoc) =
   if e.sons[0].typ.callConv == ccClosure:
     genClosureCall(p, nil, e, d)
-  elif e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags and
-      e.len >= 2:
+  elif e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags:
     genInfixCall(p, nil, e, d)
   elif e.sons[0].kind == nkSym and sfNamedParamCall in e.sons[0].sym.flags:
     genNamedParamCall(p, e, d)
@@ -462,8 +462,7 @@ proc genCall(p: BProc, e: PNode, d: var TLoc) =
 proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
   if ri.sons[0].typ.callConv == ccClosure:
     genClosureCall(p, le, ri, d)
-  elif ri.sons[0].kind == nkSym and sfInfixCall in ri.sons[0].sym.flags and
-      ri.len >= 2:
+  elif ri.sons[0].kind == nkSym and sfInfixCall in ri.sons[0].sym.flags:
     genInfixCall(p, le, ri, d)
   elif ri.sons[0].kind == nkSym and sfNamedParamCall in ri.sons[0].sym.flags:
     genNamedParamCall(p, ri, d)
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 90aefd7d6..98fb25899 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -229,8 +229,9 @@ proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
       flags - {needToCopy}
     else:
       flags
-  for i in 0 .. <dest.t.len:
-    let t = dest.t.sons[i]
+  let t = skipTypes(dest.t, abstractInst)
+  for i in 0 .. <t.len:
+    let t = t.sons[i]
     let field = ropef("Field$1", i.toRope)
     genAssignment(p, optAsgnLoc(dest, t, field), 
                      optAsgnLoc(src, t, field), newflags)
@@ -328,7 +329,9 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
       linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
   of tyObject:
     # XXX: check for subtyping?
-    if not isObjLackingTypeField(ty):
+    if ty.isImportedCppType:
+      linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
+    elif not isObjLackingTypeField(ty):
       genGenericAsgn(p, dest, src, flags)
     elif needsComplexAssignment(ty):
       if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4:
@@ -411,7 +414,7 @@ proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
   var a: TLoc
   if d.k != locNone:
     # need to generate an assignment here
-    initLoc(a, locData, getUniqueType(t), OnUnknown)
+    initLoc(a, locData, t, OnUnknown)
     a.r = r
     if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {})
     else: genAssignment(p, d, a, {needToCopy})
@@ -419,14 +422,14 @@ proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
     # we cannot call initLoc() here as that would overwrite
     # the flags field!
     d.k = locData
-    d.t = getUniqueType(t)
+    d.t = t
     d.r = r
 
 proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
   var a: TLoc
   if d.k != locNone:
     # need to generate an assignment here
-    initLoc(a, locExpr, getUniqueType(t), OnUnknown)
+    initLoc(a, locExpr, t, OnUnknown)
     a.r = r
     if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {})
     else: genAssignment(p, d, a, {needToCopy})
@@ -434,7 +437,7 @@ proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
     # we cannot call initLoc() here as that would overwrite
     # the flags field!
     d.k = locExpr
-    d.t = getUniqueType(t)
+    d.t = t
     d.r = r
 
 proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
@@ -684,7 +687,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
       # so the '&' and '*' cancel out:
       putIntoDest(p, d, a.t.sons[0], rdLoc(a))
     else:
-      putIntoDest(p, d, a.t.sons[0], ropef("(*$1)", [rdLoc(a)]))
+      putIntoDest(p, d, e.typ, ropef("(*$1)", [rdLoc(a)]))
 
 proc genAddr(p: BProc, e: PNode, d: var TLoc) =
   # careful  'addr(myptrToArray)' needs to get the ampersand:
@@ -710,7 +713,7 @@ proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc): PType =
   if e.sons[1].kind != nkSym: internalError(e.info, "genRecordFieldAux")
   d.inheritLocation(a)
   discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
-  result = a.t
+  result = a.t.getUniqueType
 
 proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
   var
@@ -719,7 +722,7 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
   initLocExpr(p, e.sons[0], a)
   d.inheritLocation(a)
   discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
-  var ty = a.t
+  var ty = a.t.getUniqueType
   var r = rdLoc(a)
   case e.sons[1].kind
   of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal)
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 12dd2a8de..90996d9cd 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -199,7 +199,7 @@ const
 
 proc cacheGetType(tab: TIdTable, key: PType): PRope = 
   # returns nil if we need to declare this type
-  # since types are now unique via the ``GetUniqueType`` mechanism, this slow
+  # since types are now unique via the ``getUniqueType`` mechanism, this slow
   # linear search is not necessary anymore:
   result = PRope(idTableGet(tab, key))
 
@@ -298,7 +298,10 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
   params = con("(", params)
 
 proc isImportedType(t: PType): bool = 
-  result = (t.sym != nil) and (sfImportc in t.sym.flags)
+  result = t.sym != nil and sfImportc in t.sym.flags
+
+proc isImportedCppType(t: PType): bool = 
+  result = t.sym != nil and sfInfixCall in t.sym.flags
 
 proc typeNameOrLiteral(t: PType, literal: string): PRope = 
   if (t.sym != nil) and (sfImportc in t.sym.flags) and (t.sym.magic == mNone): 
@@ -387,7 +390,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
     for i in countup(0, sonsLen(n) - 1): 
       app(result, genRecordFieldsAux(m, n.sons[i], accessExpr, rectype, check))
   of nkRecCase: 
-    if (n.sons[0].kind != nkSym): internalError(n.info, "genRecordFieldsAux")
+    if n.sons[0].kind != nkSym: internalError(n.info, "genRecordFieldsAux")
     app(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check))
     uname = toRope(mangle(n.sons[0].sym.name.s) & 'U')
     if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, uname])
@@ -418,12 +421,14 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
     if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname])
     else: ae = sname
     fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
-    let fieldType = field.loc.t
+    let fieldType = field.loc.t.skipTypes(abstractInst)
     if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
       appf(result, "$1 $2[SEQ_DECL_SIZE];$n",
           [getTypeDescAux(m, fieldType.elemType, check), sname])
     else:
-      appf(result, "$1 $2;$n", [getTypeDescAux(m, fieldType, check), sname])
+      # don't use fieldType here because we need the
+      # tyGenericInst for C++ template support
+      appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
   else: internalError(n.info, "genRecordFieldsAux()")
   
 proc getRecordFields(m: BModule, typ: PType, check: var IntSet): PRope = 
@@ -483,11 +488,7 @@ proc pushType(m: BModule, typ: PType) =
 
 proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope = 
   # returns only the type's name
-  var 
-    name, rettype, desc, recdesc: PRope
-    n: BiggestInt
-    t, et: PType
-  t = getUniqueType(typ)
+  var t = getUniqueType(typ)
   if t == nil: internalError("getTypeDescAux: t == nil")
   if t.sym != nil: useHeader(m, t.sym)
   result = getTypePre(m, t)
@@ -499,35 +500,42 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
     # C type generation into an analysis and a code generation phase somehow.
   case t.kind
   of tyRef, tyPtr, tyVar: 
-    et = getUniqueType(t.lastSon)
-    if et.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}: 
+    var et = t.lastSon
+    var etB = et.skipTypes(abstractInst)
+    if etB.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}: 
       # this is correct! sets have no proper base type, so we treat
       # ``var set[char]`` in `getParamTypeDesc`
-      et = getUniqueType(elemType(et))
-    case et.kind
-    of tyObject, tyTuple: 
-      # no restriction! We have a forward declaration for structs
-      name = getTypeForward(m, et)
-      result = con(name, "*")
-      idTablePut(m.typeCache, t, result)
-      pushType(m, et)
-    of tySequence: 
+      et = elemType(etB)
+      etB = et.skipTypes(abstractInst)
+    case etB.kind
+    of tyObject, tyTuple:
+      if isImportedCppType(etB) and et.kind == tyGenericInst:
+        result = con(getTypeDescAux(m, et, check), "*")
+      else:
+        # no restriction! We have a forward declaration for structs
+        let x = getUniqueType(etB)
+        let name = getTypeForward(m, x)
+        result = con(name, "*")
+        idTablePut(m.typeCache, t, result)
+        pushType(m, x)
+    of tySequence:
       # no restriction! We have a forward declaration for structs
-      name = getTypeForward(m, et)
+      let x = getUniqueType(etB)
+      let name = getTypeForward(m, x)
       result = con(name, "**")
       idTablePut(m.typeCache, t, result)
-      pushType(m, et)
-    else: 
+      pushType(m, x)
+    else:
       # else we have a strong dependency  :-(
       result = con(getTypeDescAux(m, et, check), "*")
       idTablePut(m.typeCache, t, result)
-  of tyOpenArray, tyVarargs: 
-    et = getUniqueType(t.sons[0])
-    result = con(getTypeDescAux(m, et, check), "*")
+  of tyOpenArray, tyVarargs:
+    result = con(getTypeDescAux(m, t.sons[0], check), "*")
     idTablePut(m.typeCache, t, result)
-  of tyProc: 
+  of tyProc:
     result = getTypeName(t)
     idTablePut(m.typeCache, t, result)
+    var rettype, desc: PRope
     genProcParams(m, t, rettype, desc, check)
     if not isImportedType(t): 
       if t.callConv != ccClosure: # procedure vars may need a closure!
@@ -542,7 +550,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
     # we cannot use getTypeForward here because then t would be associated
     # with the name of the struct, not with the pointer to the struct:
     result = cacheGetType(m.forwTypeCache, t)
-    if result == nil: 
+    if result == nil:
       result = getTypeName(t)
       if not isImportedType(t): 
         appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
@@ -564,27 +572,39 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
         result = toRope("TGenericSeq")
     app(result, "*")
   of tyArrayConstr, tyArray: 
-    n = lengthOrd(t)
-    if n <= 0: 
-      n = 1                   # make an array of at least one element
+    var n: BiggestInt = lengthOrd(t)
+    if n <= 0: n = 1   # make an array of at least one element
     result = getTypeName(t)
     idTablePut(m.typeCache, t, result)
-    if not isImportedType(t): 
+    if not isImportedType(t):
+      let foo = getTypeDescAux(m, t.sons[1], check)
       appf(m.s[cfsTypes], "typedef $1 $2[$3];$n", 
-           [getTypeDescAux(m, t.sons[1], check), result, toRope(n)])
-  of tyObject, tyTuple: 
-    result = cacheGetType(m.forwTypeCache, t)
-    if result == nil: 
-      result = getTypeName(t)
-      if not isImportedType(t): 
-        appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
-           [structOrUnion(t), result])
-      idTablePut(m.forwTypeCache, t, result)
-    idTablePut(m.typeCache, t, result) # always call for sideeffects:
-    if t.kind != tyTuple: recdesc = getRecordDesc(m, t, result, check)
-    else: recdesc = getTupleDesc(m, t, result, check)
-    if not isImportedType(t): app(m.s[cfsTypes], recdesc)
-  of tySet: 
+           [foo, result, toRope(n)])
+  of tyObject, tyTuple:
+    if isImportedCppType(t) and typ.kind == tyGenericInst:
+      # for instantiated templates we do not go through the type cache as the
+      # the type cache is not aware of 'tyGenericInst'.
+      result = getTypeName(t).con("<")
+      for i in 1 .. typ.len-2:
+        if i > 1: result.app(", ")
+        result.app(getTypeDescAux(m, typ.sons[i], check))
+      result.app("> ")
+      # always call for sideeffects:
+      assert t.kind != tyTuple
+      discard getRecordDesc(m, t, result, check)
+    else:
+      result = cacheGetType(m.forwTypeCache, t)
+      if result == nil:
+        result = getTypeName(t)
+        if not isImportedType(t): 
+          appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
+             [structOrUnion(t), result])
+        idTablePut(m.forwTypeCache, t, result)
+      idTablePut(m.typeCache, t, result) # always call for sideeffects:
+      let recdesc = if t.kind != tyTuple: getRecordDesc(m, t, result, check)
+                    else: getTupleDesc(m, t, result, check)
+      if not isImportedType(t): app(m.s[cfsTypes], recdesc)
+  of tySet:
     case int(getSize(t))
     of 1: result = toRope("NU8")
     of 2: result = toRope("NU16")
diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim
index 7396c0bf8..1e1fcd6fb 100644
--- a/compiler/ccgutils.nim
+++ b/compiler/ccgutils.nim
@@ -75,8 +75,7 @@ proc getUniqueType*(key: PType): PType =
   if key == nil: return 
   var k = key.kind
   case k
-  of  tyBool, tyChar, 
-      tyInt..tyUInt64:
+  of tyBool, tyChar, tyInt..tyUInt64:
     # no canonicalization for integral types, so that e.g. ``pid_t`` is
     # produced instead of ``NI``.
     result = key
@@ -86,8 +85,7 @@ proc getUniqueType*(key: PType): PType =
     if result == nil:
       gCanonicalTypes[k] = key
       result = key
-  of tyTypeDesc, tyTypeClasses, tyGenericParam,
-     tyFromExpr, tyFieldAccessor:
+  of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor:
     internalError("GetUniqueType")
   of tyDistinct:
     if key.deepCopy != nil: result = key
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index f3fa6a63e..480c131ae 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -53,7 +53,7 @@ proc emitLazily(s: PSym): bool {.inline.} =
 proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) = 
   result.k = k
   result.s = s
-  result.t = getUniqueType(typ)
+  result.t = typ
   result.r = nil
   result.flags = {}
 
@@ -61,7 +61,7 @@ proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) =
   # fills the loc if it is not already initialized
   if a.k == locNone: 
     a.k = k
-    a.t = getUniqueType(typ)
+    a.t = typ
     a.s = s
     if a.r == nil: a.r = r
   
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 17b2c4606..d94b8ade8 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -120,7 +120,7 @@ type
     warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
     warnEachIdentIsTuple, warnShadowIdent, 
     warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
-    warnUninit, warnGcMem, warnLockLevel, warnUser,
+    warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnUser,
     hintSuccess, hintSuccessX,
     hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
     hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
@@ -392,6 +392,7 @@ const
     warnGcUnsafe2: "cannot prove '$1' is GC-safe. Does not compile with --threads:on.",
     warnUninit: "'$1' might not have been initialized [Uninit]",
     warnGcMem: "'$1' uses GC'ed memory [GcMem]",
+    warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future. [Destructor]",
     warnLockLevel: "$1 [LockLevel]",
     warnUser: "$1 [User]", 
     hintSuccess: "operation successful [Success]", 
@@ -413,7 +414,7 @@ const
     hintUser: "$1 [User]"]
 
 const
-  WarningsToStr*: array[0..28, string] = ["CannotOpenFile", "OctalEscape", 
+  WarningsToStr*: array[0..29, string] = ["CannotOpenFile", "OctalEscape", 
     "XIsNeverRead", "XmightNotBeenInit",
     "Deprecated", "ConfigDeprecated",
     "SmallLshouldNotBeUsed", "UnknownMagic", 
@@ -423,7 +424,7 @@ const
     "AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap",
     "UnsafeCode", "EachIdentIsTuple", "ShadowIdent", 
     "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
-    "GcMem", "LockLevel", "User"]
+    "GcMem", "Destructor", "LockLevel", "User"]
 
   HintsToStr*: array[0..16, string] = ["Success", "SuccessX", "LineTooLong", 
     "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded", 
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 9ac7ad139..90037fccd 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -175,9 +175,15 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
                         allowed: TSymFlags): PSym
 proc semStmtScope(c: PContext, n: PNode): PNode
 
+proc typeAllowedCheck(info: TLineInfo; typ: PType; kind: TSymKind) =
+  let t = typeAllowed(typ, kind)
+  if t != nil:
+    if t == typ: localError(info, "invalid type: '" & typeToString(typ) & "'")
+    else: localError(info, "invalid type: '" & typeToString(t) & 
+                           "' in this context: '" & typeToString(typ) & "'")
+
 proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
-  if not typeAllowed(typ, skConst):
-    localError(typ.n.info, errXisNoType, typeToString(typ))
+  typeAllowedCheck(typ.n.info, typ, skConst)
 
 proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
 proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 9d9a5a50c..8221ed372 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -214,9 +214,9 @@ proc isCastable(dst, src: PType): bool =
     result = false
   elif srcSize < 0:
     result = false
-  elif not typeAllowed(dst, skParam):
+  elif typeAllowed(dst, skParam) != nil:
     result = false
-  else: 
+  else:
     result = (dstSize >= srcSize) or
         (skipTypes(dst, abstractInst).kind in IntegralTypes) or
         (skipTypes(src, abstractInst-{tyTypeDesc}).kind in IntegralTypes)
@@ -692,7 +692,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
     if callee.kind notin {skProc, skConverter} or callee.isGenericRoutine:
       return
     
-    if n.typ != nil and not typeAllowed(n.typ, skConst): return
+    if n.typ != nil and typeAllowed(n.typ, skConst) != nil: return
     
     var call = newNodeIT(nkCall, n.info, n.typ)
     call.add(n.sons[0])
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 3b90337e5..565d4db06 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -92,10 +92,10 @@ proc semProc(c: PContext, n: PNode): PNode
 include semdestruct
 
 proc semDestructorCheck(c: PContext, n: PNode, flags: TExprFlags) {.inline.} =
-  if efAllowDestructor notin flags and n.kind in nkCallKinds+{nkObjConstr}:
+  if efAllowDestructor notin flags and
+      n.kind in nkCallKinds+{nkObjConstr,nkBracket}:
     if instantiateDestructor(c, n.typ) != nil:
-      localError(n.info, errGenerated,
-        "usage of a type with a destructor in a non destructible context")
+      localError(n.info, warnDestructor)
   # This still breaks too many things:
   when false:
     if efDetermineType notin flags and n.typ.kind == tyTypeDesc and 
@@ -380,8 +380,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
       
     # this can only happen for errornous var statements:
     if typ == nil: continue
-    if not typeAllowed(typ, symkind): 
-      localError(a.info, errXisNoType, typeToString(typ))
+    typeAllowedCheck(a.info, typ, symkind)
     var tup = skipTypes(typ, {tyGenericInst})
     if a.kind == nkVarTuple: 
       if tup.kind != tyTuple: 
@@ -456,7 +455,7 @@ proc semConst(c: PContext, n: PNode): PNode =
     if typ == nil:
       localError(a.sons[2].info, errConstExprExpected)
       continue
-    if not typeAllowed(typ, skConst) and def.kind != nkNilLit:
+    if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit:
       localError(a.info, errXisNoType, typeToString(typ))
       continue
     v.typ = typ
@@ -1187,6 +1186,8 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
     else: discard
 
 proc semStaticStmt(c: PContext, n: PNode): PNode =
+  #echo "semStaticStmt"
+  #writeStackTrace()
   let a = semStmt(c, n.sons[0])
   n.sons[0] = a
   evalStaticStmt(c.module, a, c.p.owner)
diff --git a/compiler/types.nim b/compiler/types.nim
index e7841a9ab..78d390f13 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -85,8 +85,6 @@ proc analyseObjectWithTypeField*(t: PType): TTypeFieldResult
   # this does a complex analysis whether a call to ``objectInit`` needs to be
   # made or intializing of the type field suffices or if there is no type field
   # at all in this type.
-proc typeAllowed*(t: PType, kind: TSymKind): bool
-# implementation
 
 proc invalidGenericInst(f: PType): bool = 
   result = f.kind == tyGenericInst and lastSon(f) == nil
@@ -1027,22 +1025,21 @@ type
   TTypeAllowedFlags = set[TTypeAllowedFlag]
 
 proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
-                    flags: TTypeAllowedFlags = {}): bool
+                    flags: TTypeAllowedFlags = {}): PType
 
 proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind,
-                     flags: TTypeAllowedFlags = {}): bool =
-  result = true
+                     flags: TTypeAllowedFlags = {}): PType =
   if n != nil: 
     result = typeAllowedAux(marker, n.typ, kind, flags)
     #if not result: debug(n.typ)
-    if result: 
+    if result == nil:
       case n.kind
       of nkNone..nkNilLit: 
         discard
-      else: 
-        for i in countup(0, sonsLen(n) - 1): 
+      else:
+        for i in countup(0, sonsLen(n) - 1):
           result = typeAllowedNode(marker, n.sons[i], kind, flags)
-          if not result: break
+          if result != nil: break
 
 proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
                 last: TTypeKind): bool =
@@ -1054,84 +1051,88 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
   result = a.kind == last
 
 proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
-                    flags: TTypeAllowedFlags = {}): bool =
+                    flags: TTypeAllowedFlags = {}): PType =
   assert(kind in {skVar, skLet, skConst, skParam, skResult})
   # if we have already checked the type, return true, because we stop the
   # evaluation if something is wrong:
-  result = true
+  result = nil
   if typ == nil: return
-  if containsOrIncl(marker, typ.id): return 
+  if containsOrIncl(marker, typ.id): return
   var t = skipTypes(typ, abstractInst-{tyTypeDesc})
   case t.kind
   of tyVar:
-    if kind == skConst: return false
+    if kind == skConst: return t
     var t2 = skipTypes(t.sons[0], abstractInst-{tyTypeDesc})
     case t2.kind
     of tyVar: 
-      result = taHeap in flags # ``var var`` is illegal on the heap:
-    of tyOpenArray: 
-      result = kind == skParam and typeAllowedAux(marker, t2, kind, flags)
+      if taHeap notin flags: result = t2 # ``var var`` is illegal on the heap
+    of tyOpenArray:
+      if kind != skParam: result = t
+      else: result = typeAllowedAux(marker, t2, kind, flags)
     else:
-      result = kind in {skParam, skResult} and
-               typeAllowedAux(marker, t2, kind, flags)
-  of tyProc: 
+      if kind notin {skParam, skResult}: result = t
+      else: result = typeAllowedAux(marker, t2, kind, flags)
+  of tyProc:
     for i in countup(1, sonsLen(t) - 1): 
       result = typeAllowedAux(marker, t.sons[i], skParam, flags)
-      if not result: break 
-    if result and t.sons[0] != nil:
+      if result != nil: break 
+    if result.isNil and t.sons[0] != nil:
       result = typeAllowedAux(marker, t.sons[0], skResult, flags)
   of tyExpr, tyStmt, tyTypeDesc, tyStatic:
-    result = true
+    result = nil
     # XXX er ... no? these should not be allowed!
   of tyEmpty:
-    result = taField in flags
+    if taField notin flags: result = t
   of tyTypeClasses:
-    result = tfGenericTypeParam in t.flags or
-             taField notin flags
+    if not (tfGenericTypeParam in t.flags or taField notin flags): result = t
   of tyGenericBody, tyGenericParam, tyGenericInvokation,
      tyNone, tyForward, tyFromExpr, tyFieldAccessor:
-    result = false
+    result = t
   of tyNil:
-    result = kind == skConst
+    if kind != skConst: result = t
   of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer: 
-    result = true
-  of tyOrdinal: 
-    result = kind == skParam
-  of tyGenericInst, tyDistinct: 
+    result = nil
+  of tyOrdinal:
+    if kind != skParam: result = t
+  of tyGenericInst, tyDistinct:
     result = typeAllowedAux(marker, lastSon(t), kind, flags)
-  of tyRange: 
-    result = skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind in
-        {tyChar, tyEnum, tyInt..tyFloat128}
-  of tyOpenArray, tyVarargs: 
-    result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar, flags)
-  of tySequence: 
-    result = t.sons[0].kind == tyEmpty or 
-        typeAllowedAux(marker, t.sons[0], skVar, flags+{taHeap})
+  of tyRange:
+    if skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind notin
+        {tyChar, tyEnum, tyInt..tyFloat128}: result = t
+  of tyOpenArray, tyVarargs:
+    if kind != skParam: result = t
+    else: result = typeAllowedAux(marker, t.sons[0], skVar, flags)
+  of tySequence:
+    if t.sons[0].kind != tyEmpty:
+      result = typeAllowedAux(marker, t.sons[0], skVar, flags+{taHeap})
   of tyArray:
-    result = t.sons[1].kind == tyEmpty or
-        typeAllowedAux(marker, t.sons[1], skVar, flags)
+    if t.sons[1].kind != tyEmpty:
+      result = typeAllowedAux(marker, t.sons[1], skVar, flags)
   of tyRef:
-    if kind == skConst: return false
-    result = typeAllowedAux(marker, t.lastSon, skVar, flags+{taHeap})
+    if kind == skConst: result = t
+    else: result = typeAllowedAux(marker, t.lastSon, skVar, flags+{taHeap})
   of tyPtr:
     result = typeAllowedAux(marker, t.lastSon, skVar, flags+{taHeap})
   of tyArrayConstr, tySet, tyConst, tyMutable, tyIter:
     for i in countup(0, sonsLen(t) - 1):
       result = typeAllowedAux(marker, t.sons[i], kind, flags)
-      if not result: break
+      if result != nil: break
   of tyObject, tyTuple:
-    if kind == skConst and t.kind == tyObject: return false
+    if kind == skConst and t.kind == tyObject: return t
     let flags = flags+{taField}
-    for i in countup(0, sonsLen(t) - 1): 
+    for i in countup(0, sonsLen(t) - 1):
       result = typeAllowedAux(marker, t.sons[i], kind, flags)
-      if not result: break
-    if result and t.n != nil: result = typeAllowedNode(marker, t.n, kind, flags)
+      if result != nil: break
+    if result.isNil and t.n != nil:
+      result = typeAllowedNode(marker, t.n, kind, flags)
   of tyProxy:
     # for now same as error node; we say it's a valid type as it should
     # prevent cascading errors:
-    result = true
+    result = nil
 
-proc typeAllowed(t: PType, kind: TSymKind): bool = 
+proc typeAllowed*(t: PType, kind: TSymKind): PType = 
+  # returns 'nil' on success and otherwise the part of the type that is
+  # wrong!
   var marker = initIntSet()
   result = typeAllowedAux(marker, t, kind, {})
 
diff --git a/koch.nim b/koch.nim
index 13bcc3db1..432b9ff3d 100644
--- a/koch.nim
+++ b/koch.nim
@@ -61,6 +61,9 @@ Boot options:
   -d:nativeStacktrace      use native stack traces (only for Mac OS X or Linux)
   -d:noCaas                build Nimrod without CAAS support
   -d:avoidTimeMachine      only for Mac OS X, excludes nimcache dir from backups
+Web options:
+  --googleAnalytics:UA-... add the given google analytics code to the docs. To
+                           build the official docs, use UA-48159761-1
 """
 
 proc exe(f: string): string = return addFileExt(f, ExeExt)
@@ -356,6 +359,9 @@ of cmdArgument:
   of "clean": clean(op.cmdLineRest)
   of "web": web(op.cmdLineRest)
   of "website": website(op.cmdLineRest)
+  of "web0":
+    # undocumented command for Araq-the-merciful:
+    web(op.cmdLineRest & " --googleAnalytics:UA-48159761-1")
   of "pdf": pdf()
   of "csource", "csources": csource(op.cmdLineRest)
   of "zip": zip(op.cmdLineRest)
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index d9f161d49..3c1401887 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -380,17 +380,16 @@ proc format(p: MultipartData): tuple[header, body: string] =
     result.body.add("--" & bound & "\c\L" & s)
   result.body.add("--" & bound & "--\c\L")
 
-proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
-              body = "",
-              sslContext: SSLContext = defaultSSLContext,
-              timeout = -1, userAgent = defUserAgent,
-              proxy: Proxy = nil): Response =
-  ## | Requests ``url`` with the specified ``httpMethod``.
+proc request*(url: string, httpMethod: string, extraHeaders = "",
+              body = "", sslContext = defaultSSLContext, timeout = -1,
+              userAgent = defUserAgent, proxy: Proxy = nil): Response =
+  ## | Requests ``url`` with the custom method string specified by the
+  ## | ``httpMethod`` parameter.
   ## | Extra headers can be specified and must be seperated by ``\c\L``
   ## | An optional timeout can be specified in miliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
   var r = if proxy == nil: parseUri(url) else: proxy.url
-  var headers = substr($httpMethod, len("http"))
+  var headers = substr(httpMethod, len("http"))
   if proxy == nil:
     headers.add(" " & r.path)
     if r.query.len > 0:
@@ -430,9 +429,19 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
   if body != "":
     s.send(body)
 
-  result = parseResponse(s, httpMethod != httpHEAD, timeout)
+  result = parseResponse(s, httpMethod != "httpHEAD", timeout)
   s.close()
 
+proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
+              body = "", sslContext = defaultSSLContext, timeout = -1,
+              userAgent = defUserAgent, proxy: Proxy = nil): Response =
+  ## | Requests ``url`` with the specified ``httpMethod``.
+  ## | Extra headers can be specified and must be seperated by ``\c\L``
+  ## | An optional timeout can be specified in miliseconds, if reading from the
+  ## server takes longer than specified an ETimeout exception will be raised.
+  result = request(url, $httpMethod, extraHeaders, body, sslContext, timeout, 
+                   userAgent, proxy)
+
 proc redirection(status: string): bool =
   const redirectionNRs = ["301", "302", "303", "307"]
   for i in items(redirectionNRs):
@@ -556,9 +565,9 @@ proc downloadFile*(url: string, outputFilename: string,
   else:
     fileError("Unable to open file")
 
-proc generateHeaders(r: Uri, httpMethod: HttpMethod,
+proc generateHeaders(r: Uri, httpMethod: string,
                      headers: StringTableRef): string =
-  result = substr($httpMethod, len("http"))
+  result = substr(httpMethod, len("http"))
   # TODO: Proxies
   result.add(" " & r.path)
   if r.query.len > 0:
@@ -755,10 +764,10 @@ proc newConnection(client: AsyncHttpClient, url: Uri) {.async.} =
     client.currentURL = url
     client.connected = true
 
-proc request*(client: AsyncHttpClient, url: string, httpMethod = httpGET,
+proc request*(client: AsyncHttpClient, url: string, httpMethod: string,
               body = ""): Future[Response] {.async.} =
   ## Connects to the hostname specified by the URL and performs a request
-  ## using the method specified.
+  ## using the custom method string specified by ``httpMethod``.
   ##
   ## Connection will kept alive. Further requests on the same ``client`` to
   ## the same hostname will not require a new connection to be made. The
@@ -771,13 +780,25 @@ proc request*(client: AsyncHttpClient, url: string, httpMethod = httpGET,
   if not client.headers.hasKey("user-agent") and client.userAgent != "":
     client.headers["User-Agent"] = client.userAgent
 
-  var headers = generateHeaders(r, httpMethod, client.headers)
+  var headers = generateHeaders(r, $httpMethod, client.headers)
 
   await client.socket.send(headers)
   if body != "":
     await client.socket.send(body)
 
-  result = await parseResponse(client, httpMethod != httpHEAD)
+  result = await parseResponse(client, httpMethod != "httpHEAD")
+
+proc request*(client: AsyncHttpClient, url: string, httpMethod = httpGET,
+              body = ""): Future[Response] =
+  ## Connects to the hostname specified by the URL and performs a request
+  ## using the method specified.
+  ##
+  ## Connection will kept alive. Further requests on the same ``client`` to
+  ## the same hostname will not require a new connection to be made. The
+  ## connection can be closed by using the ``close`` procedure.
+  ##
+  ## The returned future will complete once the request is completed.
+  result = request(client, url, $httpMethod, body)
 
 proc get*(client: AsyncHttpClient, url: string): Future[Response] {.async.} =
   ## Connects to the hostname specified by the URL and performs a GET request.
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
index 29f6cd3ab..bd2564937 100644
--- a/lib/pure/selectors.nim
+++ b/lib/pure/selectors.nim
@@ -156,7 +156,7 @@ elif defined(linux):
       let fd = s.events[i].data.fd.SocketHandle
     
       var evSet: set[Event] = {}
-      if (s.events[i].events and EPOLLERR) != 0: evSet = evSet + {EvError}
+      if (s.events[i].events and EPOLLERR) != 0 or (s.events[i].events and EPOLLHUP) != 0: evSet = evSet + {EvError}
       if (s.events[i].events and EPOLLIN) != 0: evSet = evSet + {EvRead}
       if (s.events[i].events and EPOLLOUT) != 0: evSet = evSet + {EvWrite}
       let selectorKey = s.fds[fd]
diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim
index 1c1d973ee..8607066f3 100644
--- a/lib/pure/terminal.nim
+++ b/lib/pure/terminal.nim
@@ -185,13 +185,15 @@ proc eraseScreen* =
     var numwrote: DWORD
     var origin: TCOORD # is inititalized to 0, 0
     var hStdout = conHandle
+
     if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0:
       raiseOSError(osLastError())
-    if FillConsoleOutputCharacter(hStdout, ' ', scrbuf.dwSize.X*scrbuf.dwSize.Y,
+    let numChars = int32(scrbuf.dwSize.X)*int32(scrbuf.dwSize.Y)
+
+    if FillConsoleOutputCharacter(hStdout, ' ', numChars,
                                   origin, addr(numwrote)) == 0:
       raiseOSError(osLastError())
-    if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes,
-                                  scrbuf.dwSize.X * scrbuf.dwSize.Y,
+    if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes, numChars,
                                   origin, addr(numwrote)) == 0:
       raiseOSError(osLastError())
     setCursorXPos(0)
diff --git a/lib/system.nim b/lib/system.nim
index 57d92b28e..69a77b89b 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -2509,7 +2509,7 @@ when not defined(JS): #and not defined(NimrodVM):
     initGC()
 
   when not defined(NimrodVM):
-    proc setControlCHook*(hook: proc () {.noconv.})
+    proc setControlCHook*(hook: proc () {.noconv.} not nil)
       ## allows you to override the behaviour of your application when CTRL+C
       ## is pressed. Only one such hook is supported.
       
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 3ef0d9ce3..417a8634f 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -341,7 +341,7 @@ when not defined(noSignalHandler):
 
   registerSignalHandler() # call it in initialization section
 
-proc setControlCHook(hook: proc () {.noconv.}) =
+proc setControlCHook(hook: proc () {.noconv.} not nil) =
   # ugly cast, but should work on all architectures:
   type TSignalHandler = proc (sig: cint) {.noconv, benign.}
   c_signal(SIGINT, cast[TSignalHandler](hook))
diff --git a/tests/generics/tgeneric_inheritance.nim b/tests/generics/tgeneric_inheritance.nim
index 66b5a6c69..432228797 100644
--- a/tests/generics/tgeneric_inheritance.nim
+++ b/tests/generics/tgeneric_inheritance.nim
@@ -1,5 +1,5 @@
 discard """
-  output: '0.0'
+  output: "0.0"
 """
 
 # bug #1919
diff --git a/tests/generics/tmetafield.nim b/tests/generics/tmetafield.nim
index bbfca7e3c..7a2375abe 100644
--- a/tests/generics/tmetafield.nim
+++ b/tests/generics/tmetafield.nim
@@ -2,7 +2,7 @@ discard """
   cmd: "nim check $options $file"
   errormsg: "'proc' is not a concrete type"
   errormsg: "'Foo' is not a concrete type."
-  errormsg: "invalid type: 'TBaseMed'"
+  errormsg: "invalid type: 'proc' in this context: 'TBaseMed'"
 """
 
 type
diff --git a/web/community.txt b/web/community.txt
index 5c0d30856..5d9343c98 100644
--- a/web/community.txt
+++ b/web/community.txt
@@ -14,6 +14,16 @@ Nim's Community
 
 .. container:: standout
 
+  Mailing list
+  ------------
+
+  The mailing list can be found here: http://www.freelists.org/list/nim-dev
+  There is no consensus yet about what is discussed via the forum as opposed
+  to the mailing list. Join whatever you like!
+
+
+.. container:: standout
+
   IRC
   ----