summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2014-03-10 22:23:38 +0100
committerAraq <rumpf_a@web.de>2014-03-10 22:23:38 +0100
commit3270676e77676335446287fcff05aa6a6b9b4919 (patch)
tree4bd724bed5ae887efa9d8f97494755715980ca20
parent121553d1a69c4d175259944f6bdc9f9dcfda9cdd (diff)
parent1546d210c5739213ebf93eb0cb624ca7a9fe9ad6 (diff)
downloadNim-3270676e77676335446287fcff05aa6a6b9b4919.tar.gz
Merge branch 'devel' of https://github.com/Araq/Nimrod into devel
-rw-r--r--compiler/ast.nim4
-rw-r--r--compiler/astalgo.nim8
-rw-r--r--compiler/guards.nim4
-rw-r--r--compiler/msgs.nim6
-rw-r--r--compiler/sem.nim7
-rw-r--r--compiler/semcall.nim12
-rw-r--r--compiler/semexprs.nim62
-rw-r--r--compiler/seminst.nim2
-rw-r--r--compiler/semstmts.nim18
-rw-r--r--compiler/semtempl.nim4
-rw-r--r--compiler/semtypes.nim99
-rw-r--r--compiler/semtypinst.nim16
-rw-r--r--compiler/sigmatch.nim19
-rw-r--r--compiler/transf.nim12
-rw-r--r--compiler/vm.nim4
-rw-r--r--doc/manual.txt24
-rw-r--r--lib/impure/db_mysql.nim10
-rw-r--r--lib/nimbase.h3
-rw-r--r--lib/posix/epoll.nim2
-rw-r--r--lib/pure/asyncio2.nim28
-rw-r--r--lib/pure/selectors.nim26
-rw-r--r--lib/pure/sockets2.nim22
-rw-r--r--lib/system.nim53
-rw-r--r--tests/async/tasyncawait.nim10
-rw-r--r--tests/generics/tgenericshardcases.nim18
-rw-r--r--tests/iter/tchainediterators.nim38
-rw-r--r--tests/iter/titerable.nim26
-rw-r--r--tests/metatype/tstaticparams.nim26
-rw-r--r--tests/overload/tissue966.nim12
-rw-r--r--tests/static/tstaticparammacro.nim52
-rw-r--r--tests/system/alloc.nim37
-rw-r--r--tests/template/tissue909.nim16
-rw-r--r--tests/testament/htmlgen.nim18
-rw-r--r--tests/vm/tstaticprintseq.nim36
34 files changed, 567 insertions, 167 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 9c9dfce9a..f9cab0d88 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -818,6 +818,9 @@ type
     counter*: int
     data*: TObjectSeq
 
+  TImplication* = enum
+    impUnknown, impNo, impYes
+
 # BUGFIX: a module is overloadable so that a proc can have the
 # same name as an imported module. This is necessary because of
 # the poor naming choices in the standard library.
@@ -865,6 +868,7 @@ const
   nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix,
                   nkCommand, nkCallStrLit, nkHiddenCallConv}
 
+  nkLiterals* = {nkCharLit..nkTripleStrLit}
   nkLambdaKinds* = {nkLambda, nkDo}
   declarativeDefs* = {nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef}
   procDefs* = nkLambdaKinds + declarativeDefs
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index cce2cc215..36dd7f562 100644
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -50,7 +50,7 @@ proc strTableGet*(t: TStrTable, name: PIdent): PSym
 type 
   TTabIter*{.final.} = object # consider all fields here private
     h*: THash                 # current hash
-  
+
 proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym
 proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym
   # usage:
@@ -157,6 +157,12 @@ proc leValue*(a, b: PNode): bool =
     #InternalError(a.info, "leValue")
     discard
 
+proc weakLeValue*(a, b: PNode): TImplication =
+  if a.kind notin nkLiterals or b.kind notin nkLiterals:
+    result = impUnknown
+  else:
+    result = if leValue(a, b): impYes else: impNo
+
 proc lookupInRecord(n: PNode, field: PIdent): PSym = 
   result = nil
   case n.kind
diff --git a/compiler/guards.nim b/compiler/guards.nim
index fe868054f..f475f5068 100644
--- a/compiler/guards.nim
+++ b/compiler/guards.nim
@@ -274,10 +274,6 @@ proc pred(n: PNode): PNode =
   else:
     result = n
 
-type
-  TImplication* = enum
-    impUnknown, impNo, impYes  
-
 proc impliesEq(fact, eq: PNode): TImplication =
   let (loc, val) = if isLocation(eq.sons[1]): (1, 2) else: (2, 1)
   
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 66763e7f5..5bc490d14 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -96,8 +96,8 @@ type
     errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
     errMacroBodyDependsOnGenericTypes,
     errDestructorNotGenericEnough,
-    
-    errXExpectsTwoArguments, 
+    errInlineIteratorsAsProcParams,
+    errXExpectsTwoArguments,
     errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations, 
     errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX, 
     errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument, 
@@ -331,6 +331,8 @@ const
                                        "because the parameter '$1' has a generic type",
     errDestructorNotGenericEnough: "Destructor signarue is too specific. " &
                                    "A destructor must be associated will all instantiations of a generic type",
+    errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " &
+                                    "templates, macros and other inline iterators",
     errXExpectsTwoArguments: "\'$1\' expects two arguments", 
     errXExpectsObjectTypes: "\'$1\' expects object types",
     errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype", 
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 5ee46654e..c8228618b 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -139,6 +139,10 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
     result = n.sym
     internalAssert sfGenSym in result.flags
     internalAssert result.kind == kind
+    # when there is a nested proc inside a template, semtmpl
+    # will assign a wrong owner during the first pass over the
+    # template; we must fix it here: see #909
+    result.owner = getCurrOwner()
   else:
     result = newSym(kind, considerAcc(n), getCurrOwner(), n.info)
 
@@ -194,7 +198,8 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
       result = semExprWithType(c, evaluated)
     else:
       result = evaluated
-      semmacrosanity.annotateType(result, eOrig.typ)
+      let expectedType = eOrig.typ.skipTypes({tyStatic})
+      semmacrosanity.annotateType(result, expectedType)
   else:
     result = semExprWithType(c, evaluated)
     #result = fitNode(c, e.typ, result) inlined with special case:
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 2e5def75a..5d480bc98 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -82,7 +82,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: seq[string]) =
     # fail fast:
     globalError(n.info, errTypeMismatch, "")
   var result = msgKindToString(errTypeMismatch)
-  add(result, describeArgs(c, n, 1 + ord(nfDotField in n.flags)))
+  add(result, describeArgs(c, n, 1))
   add(result, ')')
   
   var candidates = ""
@@ -114,7 +114,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
 
   var errors: seq[string]
   var usedSyms: seq[PNode]
- 
+
   template pickBest(headSymbol: expr) =
     pickBestCandidate(c, headSymbol, n, orig, initialBinding,
                       filter, result, alt, errors)
@@ -166,7 +166,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
       n.sons[0..1] = [callOp, n[1], calleeName]
       orig.sons[0..1] = [callOp, orig[1], calleeName]
       pickBest(callOp)
-    
+   
     if overloadsState == csEmpty and result.state == csEmpty:
       localError(n.info, errUndeclaredIdentifier, considerAcc(f).s)
       return
@@ -175,9 +175,15 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
         localError(n.info, errExprXCannotBeCalled,
                    renderTree(n, {renderNoComments}))
       else:
+        if {nfDotField, nfDotSetter} * n.flags != {}:
+          # clean up the inserted ops
+          n.sons.delete(2)
+          n.sons[0] = f
+
         errors = @[]
         pickBest(f)
         notFoundError(c, n, errors)
+
       return
 
   if alt.state == csMatch and cmpCandidates(result, alt) == 0 and
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 203a51816..62a816a50 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -885,7 +885,7 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
   of nkSym: 
     if r.sym.name.id == field.id: result = r.sym
   else: illFormedAst(n)
-  
+
 proc makeDeref(n: PNode): PNode = 
   var t = skipTypes(n.typ, {tyGenericInst})
   result = n
@@ -899,6 +899,21 @@ proc makeDeref(n: PNode): PNode =
     addSon(result, a)
     t = skipTypes(t.sons[0], {tyGenericInst})
 
+proc readTypeParameter(c: PContext, ty: PType,
+                       paramName: PIdent, info: TLineInfo): PNode =
+  internalAssert ty.kind == tyGenericInst
+  let ty = ty.skipGenericAlias
+  let tbody = ty.sons[0]
+  for s in countup(0, tbody.len-2):
+    let tParam = tbody.sons[s]
+    if tParam.sym.name == paramName:
+      let rawTyp = ty.sons[s + 1]
+      if rawTyp.kind == tyStatic:
+        return rawTyp.n
+      else:
+        let foundTyp = makeTypeDesc(c, rawTyp)
+        return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
+
 proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
   ## returns nil if it's not a built-in field access
   checkSonsLen(n, 2)
@@ -916,7 +931,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
   var ty = n.sons[0].typ
   var f: PSym = nil
   result = nil
-  if isTypeExpr(n.sons[0]) or ty.kind == tyTypeDesc and ty.base.kind != tyNone:
+  if isTypeExpr(n.sons[0]) or (ty.kind == tyTypeDesc and ty.base.kind != tyNone):
     if ty.kind == tyTypeDesc: ty = ty.base
     case ty.kind
     of tyEnum:
@@ -925,28 +940,17 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
         f = getSymFromList(ty.n, i)
         if f != nil: break 
         ty = ty.sons[0]         # enum inheritance
-      if f != nil: 
+      if f != nil:
         result = newSymNode(f)
         result.info = n.info
         result.typ = ty
         markUsed(n, f)
         return
     of tyGenericInst:
-      assert ty.sons[0].kind == tyGenericBody
-      let tbody = ty.sons[0]
-      for s in countup(0, tbody.len-2):
-        let tParam = tbody.sons[s]
-        if tParam.sym.name == i:
-          let rawTyp = ty.sons[s + 1]
-          if rawTyp.kind == tyStatic:
-            return rawTyp.n
-          else:
-            let foundTyp = makeTypeDesc(c, rawTyp)
-            return newSymNode(copySym(tParam.sym).linkTo(foundTyp), n.info)
-      return
+      return readTypeParameter(c, ty, i, n.info)
     of tyObject, tyTuple:
       if ty.n.kind == nkRecList:
-        for field in ty.n.sons:
+        for field in ty.n:
           if field.sym.name == i:
             n.typ = newTypeWithSons(c, tyFieldAccessor, @[ty, field.sym.typ])
             n.typ.n = copyTree(n)
@@ -958,6 +962,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
     # XXX: This is probably not relevant any more
     # reset to prevent 'nil' bug: see "tests/reject/tenumitems.nim":
     ty = n.sons[0].typ
+    return nil
     
   ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef})
   var check: PNode = nil
@@ -990,6 +995,10 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
       n.typ = f.typ
       result = n
 
+  # we didn't find any field, let's look for a generic param
+  if result == nil and n.sons[0].typ.kind == tyGenericInst:
+    result = readTypeParameter(c, n.sons[0].typ, i, n.info)
+
 proc dotTransformation(c: PContext, n: PNode): PNode =
   if isSymChoice(n.sons[1]):
     result = newNodeI(nkDotCall, n.info)
@@ -1119,6 +1128,9 @@ proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
       n.sons[0] = x # 'result[]' --> 'result'
       n.sons[1] = takeImplicitAddr(c, ri)
 
+template resultTypeIsInferrable(typ: PType): expr =
+  typ.isMetaType and typ.kind != tyTypeDesc
+
 proc semAsgn(c: PContext, n: PNode): PNode =
   checkSonsLen(n, 2)
   var a = n.sons[0]
@@ -1170,7 +1182,7 @@ proc semAsgn(c: PContext, n: PNode): PNode =
         if lhsIsResult: {efAllowDestructor} else: {})
     if lhsIsResult:
       n.typ = enforceVoidContext
-      if lhs.sym.typ.isMetaType and lhs.sym.typ.kind != tyTypeDesc:
+      if resultTypeIsInferrable(lhs.sym.typ):
         if cmpTypes(c, lhs.typ, rhs.typ) == isGeneric:
           internalAssert c.p.resultSym != nil
           lhs.typ = rhs.typ
@@ -1259,12 +1271,21 @@ proc semYield(c: PContext, n: PNode): PNode =
     localError(n.info, errYieldNotAllowedInTryStmt)
   elif n.sons[0].kind != nkEmpty:
     n.sons[0] = semExprWithType(c, n.sons[0]) # check for type compatibility:
-    var restype = c.p.owner.typ.sons[0]
+    var iterType = c.p.owner.typ
+    var restype = iterType.sons[0]
     if restype != nil:
       let adjustedRes = if c.p.owner.kind == skIterator: restype.base
                         else: restype
       n.sons[0] = fitNode(c, adjustedRes, n.sons[0])
       if n.sons[0].typ == nil: internalError(n.info, "semYield")
+      
+      if resultTypeIsInferrable(adjustedRes):
+        let inferred = n.sons[0].typ
+        if c.p.owner.kind == skIterator:
+          iterType.sons[0].sons[0] = inferred
+        else:
+          iterType.sons[0] = inferred
+      
       semYieldVarResult(c, n, adjustedRes)
     else:
       localError(n.info, errCannotReturnExpr)
@@ -1346,7 +1367,7 @@ proc expectString(c: PContext, n: PNode): string =
     localError(n.info, errStringLiteralExpected)
 
 proc getMagicSym(magic: TMagic): PSym =
-  result = newSym(skProc, getIdent($magic), getCurrOwner(), gCodegenLineInfo)
+  result = newSym(skProc, getIdent($magic), systemModule, gCodegenLineInfo)
   result.magic = magic
 
 proc newAnonSym(kind: TSymKind, info: TLineInfo,
@@ -1939,7 +1960,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkBracketExpr:
     checkMinSonsLen(n, 1)
     var s = qualifiedLookUp(c, n.sons[0], {checkUndeclared})
-    if s != nil and s.kind in {skProc, skMethod, skConverter}+skIterators:
+    if (s != nil and s.kind in {skProc, skMethod, skConverter}+skIterators) or
+        n[0].kind in nkSymChoices:
       # type parameters: partial generic specialization
       n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s)
       result = explicitGenericInstantiation(c, n, s)
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 8faf1d21a..4bcfa7f15 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -20,7 +20,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
     if a.kind != nkSym: 
       internalError(a.info, "instantiateGenericParamList; no symbol")
     var q = a.sym
-    if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic}+tyTypeClasses:
+    if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic, tyIter}+tyTypeClasses:
       continue
     var s = newSym(skType, q.name, getCurrOwner(), q.info)
     s.flags = s.flags + {sfUsed, sfFromGeneric}
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index a11386966..edce7c9bd 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -661,10 +661,18 @@ proc semFor(c: PContext, n: PNode): PNode =
   openScope(c)
   n.sons[length-2] = semExprNoDeref(c, n.sons[length-2], {efWantIterator})
   var call = n.sons[length-2]
-  if call.kind in nkCallKinds and call.sons[0].typ.callConv == ccClosure:
+  let isCallExpr = call.kind in nkCallKinds
+  if isCallExpr and call.sons[0].sym.magic != mNone:
+    if call.sons[0].sym.magic == mOmpParFor:
+      result = semForVars(c, n)
+      result.kind = nkParForStmt
+    else:
+      result = semForFields(c, n, call.sons[0].sym.magic)
+  elif (isCallExpr and call.sons[0].typ.callConv == ccClosure) or
+      call.typ.kind == tyIter:
     # first class iterator:
     result = semForVars(c, n)
-  elif call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
+  elif not isCallExpr or call.sons[0].kind != nkSym or
       call.sons[0].sym.kind notin skIterators:
     if length == 3:
       n.sons[length-2] = implicitIterator(c, "items", n.sons[length-2])
@@ -673,12 +681,6 @@ proc semFor(c: PContext, n: PNode): PNode =
     else:
       localError(n.sons[length-2].info, errIteratorExpected)
     result = semForVars(c, n)
-  elif call.sons[0].sym.magic != mNone:
-    if call.sons[0].sym.magic == mOmpParFor:
-      result = semForVars(c, n)
-      result.kind = nkParForStmt
-    else:
-      result = semForFields(c, n, call.sons[0].sym.magic)
   else:
     result = semForVars(c, n)
   # propagate any enforced VoidContext:
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 31624a97f..42268d44f 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -348,7 +348,9 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
   of nkMethodDef:
     result = semRoutineInTemplBody(c, n, skMethod)
   of nkIteratorDef:
-    result = semRoutineInTemplBody(c, n, n[namePos].sym.kind)
+    let kind = if hasPragma(n[pragmasPos], wClosure): skClosureIterator
+               else: skIterator
+    result = semRoutineInTemplBody(c, n, kind)
   of nkTemplateDef:
     result = semRoutineInTemplBody(c, n, skTemplate)
   of nkMacroDef:
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index a619de7ff..f91222477 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -147,26 +147,38 @@ proc semDistinct(c: PContext, n: PNode, prev: PType): PType =
   else:
     result = newConstraint(c, tyDistinct)
   
-proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = 
+proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
   assert isRange(n)
   checkSonsLen(n, 3)
   result = newOrPrevType(tyRange, prev, c)
   result.n = newNodeI(nkRange, n.info)
-  if (n[1].kind == nkEmpty) or (n[2].kind == nkEmpty): 
+  if (n[1].kind == nkEmpty) or (n[2].kind == nkEmpty):
     localError(n.info, errRangeIsEmpty)
-  var a = semConstExpr(c, n[1])
-  var b = semConstExpr(c, n[2])
-  if not sameType(a.typ, b.typ):
+  
+  var range: array[2, PNode]
+  range[0] = semExprWithType(c, n[1], {efDetermineType})
+  range[1] = semExprWithType(c, n[2], {efDetermineType})
+  
+  var rangeT: array[2, PType]
+  for i in 0..1: rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit
+
+  if not sameType(rangeT[0], rangeT[1]):
     localError(n.info, errPureTypeMismatch)
-  elif a.typ.kind notin {tyInt..tyInt64,tyEnum,tyBool,tyChar,
-                         tyFloat..tyFloat128,tyUInt8..tyUInt32}:
+  elif not rangeT[0].isOrdinalType:
     localError(n.info, errOrdinalTypeExpected)
-  elif enumHasHoles(a.typ): 
-    localError(n.info, errEnumXHasHoles, a.typ.sym.name.s)
-  elif not leValue(a, b): localError(n.info, errRangeIsEmpty)
-  addSon(result.n, a)
-  addSon(result.n, b)
-  addSonSkipIntLit(result, b.typ)
+  elif enumHasHoles(rangeT[0]):
+    localError(n.info, errEnumXHasHoles, rangeT[0].sym.name.s)
+  
+  for i in 0..1:
+    if hasGenericArguments(range[i]):
+      result.n.addSon makeStaticExpr(c, range[i])
+    else:
+      result.n.addSon semConstExpr(c, range[i])
+ 
+  if weakLeValue(result.n[0], result.n[1]) == impNo:
+    localError(n.info, errRangeIsEmpty)
+
+  addSonSkipIntLit(result, rangeT[0])
 
 proc semRange(c: PContext, n: PNode, prev: PType): PType =
   result = nil
@@ -602,15 +614,24 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
     incl(result.flags, tfFinal)
 
 proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
-  if kind == skMacro and param.typ.kind notin {tyTypeDesc, tyStatic}:
-    # within a macro, every param has the type PNimrodNode!
-    # and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}:
-    let nn = getSysSym"PNimrodNode"
-    var a = copySym(param)
-    a.typ = nn.typ
-    if sfGenSym notin a.flags: addDecl(c, a)
+  template addDecl(x) =
+    if sfGenSym notin x.flags: addDecl(c, x)
+
+  if kind == skMacro:
+    if param.typ.kind == tyTypeDesc:
+      addDecl(param)
+    elif param.typ.kind == tyStatic:
+      var a = copySym(param)
+      a.typ = param.typ.base
+      addDecl(a)
+    else:
+      # within a macro, every param has the type PNimrodNode!
+      let nn = getSysSym"PNimrodNode"
+      var a = copySym(param)
+      a.typ = nn.typ
+      addDecl(a)
   else:
-    if sfGenSym notin param.flags: addDecl(c, param)
+    addDecl(param)
 
 let typedescId = getIdent"typedesc"
 
@@ -721,7 +742,16 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
                                   allowMetaTypes = true)
     result = newTypeWithSons(c, tyCompositeTypeClass, @[paramType, result])
     result = addImplicitGeneric(result)
-  
+
+  of tyIter:
+    if paramType.callConv == ccInline:
+      if procKind notin {skTemplate, skMacro, skIterator}:
+        localError(info, errInlineIteratorsAsProcParams)
+      if paramType.len == 1:
+        let lifted = liftingWalk(paramType.base)
+        if lifted != nil: paramType.sons[0] = lifted
+      result = addImplicitGeneric(paramType)
+
   of tyGenericInst:
     if paramType.lastSon.kind == tyUserTypeClass:
       var cp = copyType(paramType, getCurrOwner(), false)
@@ -840,9 +870,13 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       addParamOrResult(c, arg, kind)
       if gCmd == cmdPretty: checkDef(a.sons[j], arg)
 
-
+  var r: PType
   if n.sons[0].kind != nkEmpty:
-    var r = semTypeNode(c, n.sons[0], nil)
+    r = semTypeNode(c, n.sons[0], nil)
+  elif kind == skIterator:
+    r = newTypeS(tyAnything, c)
+  
+  if r != nil:
     # turn explicit 'void' return type into 'nil' because the rest of the 
     # compiler only checks for 'nil':
     if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
@@ -852,7 +886,11 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
         if lifted != nil: r = lifted
         r.flags.incl tfRetType
       r = skipIntLit(r)
-      if kind == skIterator: r = newTypeWithSons(c, tyIter, @[r])
+      if kind == skIterator:
+        # see tchainediterators
+        # in cases like iterator foo(it: iterator): type(it)
+        # we don't need to change the return type to iter[T]
+        if not r.isInlineIterator: r = newTypeWithSons(c, tyIter, @[r])
       result.sons[0] = r
       res.typ = r
 
@@ -984,7 +1022,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   of nkTypeOfExpr:
     # for ``type(countup(1,3))``, see ``tests/ttoseq``.
     checkSonsLen(n, 1)
-    result = semExprWithType(c, n.sons[0], {efInTypeof}).typ.skipTypes({tyIter})
+    let typExpr = semExprWithType(c, n.sons[0], {efInTypeof})
+    result = typExpr.typ.skipTypes({tyIter})
   of nkPar: 
     if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
     else:
@@ -1103,8 +1142,12 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
       result = newConstraint(c, tyIter)
     else:
       result = semProcTypeWithScope(c, n, prev, skClosureIterator)
-      result.flags.incl(tfIterator)
-      result.callConv = ccClosure
+      if n.lastSon.kind == nkPragma and hasPragma(n.lastSon, wInline):
+        result.kind = tyIter
+        result.callConv = ccInline
+      else:
+        result.flags.incl(tfIterator)
+        result.callConv = ccClosure
   of nkProcTy:
     if n.sonsLen == 0:
       result = newConstraint(c, tyProc)
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 22edc6e32..80e2aa284 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -181,7 +181,8 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
   of nkStaticExpr:
     var n = prepareNode(cl, n)
     n = reResolveCallsWithTypedescParams(cl, n)
-    result = cl.c.semExpr(cl.c, n)
+    result = if cl.allowMetaTypes: n
+             else: cl.c.semExpr(cl.c, n)
   else:
     var length = sonsLen(n)
     if length > 0:
@@ -305,6 +306,11 @@ proc skipIntLiteralParams(t: PType) =
     if skipped != p:
       t.sons[i] = skipped
       if i > 0: t.n.sons[i].sym.typ = skipped
+  
+  # when the typeof operator is used on a static input
+  # param, the results gets infected with static as well:
+  if t.sons[0] != nil and t.sons[0].kind == tyStatic:
+    t.sons[0] = t.sons[0].base
 
 proc propagateFieldFlags(t: PType, n: PNode) =
   # This is meant for objects and tuples
@@ -314,16 +320,15 @@ proc propagateFieldFlags(t: PType, n: PNode) =
   of nkSym:
     propagateToOwner(t, n.sym.typ)
   of nkRecList, nkRecCase, nkOfBranch, nkElse:
-    if n.sons != nil:
-      for son in n.sons:
-        propagateFieldFlags(t, son)
+    for son in n:
+      propagateFieldFlags(t, son)
   else: discard
 
 proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
   result = t
   if t == nil: return
 
-  if t.kind in {tyStatic, tyGenericParam} + tyTypeClasses:
+  if t.kind in {tyStatic, tyGenericParam, tyIter} + tyTypeClasses:
     let lookup = PType(idTableGet(cl.typeMap, t))
     if lookup != nil: return lookup
   
@@ -336,6 +341,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
     result = replaceTypeVarsT(cl, lastSon(t))
 
   of tyFromExpr:
+    if cl.allowMetaTypes: return
     var n = prepareNode(cl, t.n)
     n = cl.c.semConstExpr(cl.c, n)
     if n.typ.kind == tyTypeDesc:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index c0898ef26..19f10def8 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -1014,6 +1014,10 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
       result.typ = getInstantiatedType(c, arg, m, base(f))
     m.baseTypeMatch = true
 
+proc isInlineIterator*(t: PType): bool =
+  result = t.kind == tyIter or
+          (t.kind == tyBuiltInTypeClass and t.base.kind == tyIter)
+
 proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
                         argSemantized, argOrig: PNode): PNode =
   var
@@ -1021,7 +1025,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
     arg = argSemantized
     argType = argType
     c = m.c
-    
+   
   if tfHasStatic in fMaybeStatic.flags:
     # XXX: When implicit statics are the default
     # this will be done earlier - we just have to
@@ -1060,7 +1064,14 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
       return arg.typ.n
     else:
       return argOrig
-  
+
+  if r != isNone and f.isInlineIterator:
+    var inlined = newTypeS(tyStatic, c)
+    inlined.sons = @[argType]
+    inlined.n = argSemantized
+    put(m.bindings, f, inlined)
+    return argSemantized
+
   case r
   of isConvertible:
     inc(m.convMatches)
@@ -1188,7 +1199,9 @@ proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode =
     # a.typ == nil is valid
     result = a
   elif a.typ.isNil:
-    result = c.semOperand(c, a, {efDetermineType})
+    let flags = if formal.kind == tyIter: {efDetermineType, efWantIterator}
+                else: {efDetermineType}
+    result = c.semOperand(c, a, flags)
   else:
     result = a
 
diff --git a/compiler/transf.nim b/compiler/transf.nim
index f4b716c5b..9586398c9 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -425,7 +425,7 @@ proc findWrongOwners(c: PTransf, n: PNode) =
         x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
   else:
     for i in 0 .. <safeLen(n): findWrongOwners(c, n.sons[i])
-  
+
 proc transformFor(c: PTransf, n: PNode): PTransNode = 
   # generate access statements for the parameters (unless they are constant)
   # put mapping from formal parameters to actual parameters
@@ -433,12 +433,13 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
 
   var length = sonsLen(n)
   var call = n.sons[length - 2]
-  if call.kind notin nkCallKinds or call.sons[0].kind != nkSym or 
-      call.sons[0].sym.kind != skIterator:
+  if call.typ.kind != tyIter and
+    (call.kind notin nkCallKinds or call.sons[0].kind != nkSym or 
+      call.sons[0].sym.kind != skIterator):
     n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
     return lambdalifting.liftForLoop(n).PTransNode
     #InternalError(call.info, "transformFor")
-
+  
   #echo "transforming: ", renderTree(n)
   result = newTransNode(nkStmtList, n.info, 0)
   var loopBody = transformLoopBody(c, n.sons[length-1])
@@ -459,6 +460,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
   for i in countup(1, sonsLen(call) - 1): 
     var arg = transform(c, call.sons[i]).PNode
     var formal = skipTypes(iter.typ, abstractInst).n.sons[i].sym 
+    if arg.typ.kind == tyIter: continue
     case putArgInto(arg, formal.typ)
     of paDirectMapping: 
       idNodeTablePut(newC.mapping, formal, arg)
@@ -480,7 +482,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
   dec(c.inlining)
   popInfoContext()
   popTransCon(c)
-  #echo "transformed: ", renderTree(n)
+  # echo "transformed: ", result.PNode.renderTree
   
 proc getMagicOp(call: PNode): TMagic = 
   if call.sons[0].kind == nkSym and
diff --git a/compiler/vm.nim b/compiler/vm.nim
index f9b143bce..2a80106a5 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -425,7 +425,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       decodeBC(rkNode)
       let src = regs[rb].node
       if src.kind notin {nkEmpty..nkNilLit}:
-        regs[ra].node = src.sons[rc]
+        let n = src.sons[rc]
+        regs[ra].node = if n.kind == nkExprColonExpr: n[1]
+                        else: n
       else:
         stackTrace(c, tos, pc, errIndexOutOfBounds)
     of opcWrObj:
diff --git a/doc/manual.txt b/doc/manual.txt
index 04c69cf94..ab1badaf3 100644
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -2875,7 +2875,6 @@ as there are components in the tuple. The i'th iteration variable's type is
 the type of the i'th component. In other words, implicit tuple unpacking in a 
 for loop context is supported.
 
-
 Implict items/pairs invocations
 -------------------------------
 
@@ -2900,10 +2899,11 @@ First class iterators
 There are 2 kinds of iterators in Nimrod: *inline* and *closure* iterators.
 An `inline iterator`:idx: is an iterator that's always inlined by the compiler 
 leading to zero overhead for the abstraction, but may result in a heavy
-increase in code size. Inline iterators are second class
-citizens; one cannot pass them around like first class procs.
+increase in code size. Inline iterators are second class citizens;
+They can be passed as parameters only to other inlining code facilities like
+templates, macros and other inline iterators.
 
-In contrast to that, a `closure iterator`:idx: can be passed around:
+In contrast to that, a `closure iterator`:idx: can be passed around more freely:
 
 .. code-block:: nimrod
   iterator count0(): int {.closure.} =
@@ -2926,9 +2926,7 @@ Closure iterators have other restrictions than inline iterators:
 1. ``yield`` in a closure iterator can not occur in a ``try`` statement.
 2. For now, a closure iterator cannot be evaluated at compile time.
 3. ``return`` is allowed in a closure iterator (but rarely useful).
-4. Since closure iterators can be used as a collaborative tasking
-   system, ``void`` is a valid return type for them.
-5. Both inline and closure iterators cannot be recursive.
+4. Both inline and closure iterators cannot be recursive.
 
 Iterators that are neither marked ``{.closure.}`` nor ``{.inline.}`` explicitly
 default to being inline, but that this may change in future versions of the
@@ -2990,6 +2988,14 @@ parameters of an outer factory proc:
   for f in foo():
     echo f
 
+Implicit return type
+--------------------
+
+Since inline interators must always produce values that will be consumed in
+a for loop, the compiler will implicity use the ``auto`` return type if no
+type is given by the user. In contrast, since closure iterators can be used
+as a collaborative tasking system, ``void`` is a valid return type for them.
+
 
 Type sections
 =============
@@ -4069,8 +4075,8 @@ Static params can also appear in the signatures of generic types:
     AffineTransform2D[T] = Matrix[3, 3, T]
     AffineTransform3D[T] = Matrix[4, 4, T]
 
-  AffineTransform3D[float]  # OK
-  AffineTransform2D[string] # Error, `string` is not a `Number`
+  var m1: AffineTransform3D[float]  # OK
+  var m2: AffineTransform2D[string] # Error, `string` is not a `Number`
 
 
 typedesc
diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim
index 74aaa1a59..32cda3e4d 100644
--- a/lib/impure/db_mysql.nim
+++ b/lib/impure/db_mysql.nim
@@ -195,8 +195,14 @@ proc open*(connection, user, password, database: string): TDbConn {.
   ## be established.
   result = mysql.Init(nil)
   if result == nil: dbError("could not open database connection") 
-  if mysql.RealConnect(result, "", user, password, database, 
-                       0'i32, nil, 0) == nil:
+  let
+    colonPos = connection.find(':')
+    host =        if colonPos < 0: connection
+                  else:            substr(connection, 0, colonPos-1)
+    port: int32 = if colonPos < 0: 0'i32
+                  else:            substr(connection, colonPos+1).parseInt.int32
+  if mysql.RealConnect(result, host, user, password, database, 
+                       port, nil, 0) == nil:
     var errmsg = $mysql.error(result)
     db_mysql.Close(result)
     dbError(errmsg)
diff --git a/lib/nimbase.h b/lib/nimbase.h
index 1100e084b..b16b27b2c 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -314,6 +314,9 @@ static unsigned long nimNaN[2]={0xffffffff, 0x7fffffff};
 #    define INF INFINITY
 #  elif defined(HUGE_VAL)
 #    define INF  HUGE_VAL
+#  elif defined(_MSC_VER)
+#    include <float.h>
+#    define INF (DBL_MAX+DBL_MAX)
 #  else
 #    define INF (1.0 / 0.0)
 #  endif
diff --git a/lib/posix/epoll.nim b/lib/posix/epoll.nim
index 366521551..57a2f001f 100644
--- a/lib/posix/epoll.nim
+++ b/lib/posix/epoll.nim
@@ -36,7 +36,7 @@ type
   epoll_data* {.importc: "union epoll_data", 
       header: "<sys/epoll.h>", pure, final.} = object # TODO: This is actually a union.
     #thePtr* {.importc: "ptr".}: pointer
-    fd*: cint # \
+    fd* {.importc: "fd".}: cint # \
     #u32*: uint32
     #u64*: uint64
 
diff --git a/lib/pure/asyncio2.nim b/lib/pure/asyncio2.nim
index 12d4cb5a3..60d489dda 100644
--- a/lib/pure/asyncio2.nim
+++ b/lib/pure/asyncio2.nim
@@ -473,7 +473,6 @@ else:
 
   proc update(p: PDispatcher, sock: TSocketHandle, events: set[TEvent]) =
     assert sock in p.selector
-    echo("Update: ", events)
     if events == {}:
       discard p.selector.unregister(sock)
     else:
@@ -499,23 +498,25 @@ else:
     for info in p.selector.select(timeout):
       let data = PData(info.key.data)
       assert data.sock == info.key.fd
-      echo("R: ", data.readCBs.len, " W: ", data.writeCBs.len, ". ", info.events)
       
       if EvRead in info.events:
-        var newReadCBs: seq[TCallback] = @[]
-        for cb in data.readCBs:
+        # Callback may add items to ``data.readCBs`` which causes issues if
+        # we are iterating over ``data.readCBs`` at the same time. We therefore
+        # make a copy to iterate over.
+        let currentCBs = data.readCBs
+        data.readCBs = @[]
+        for cb in currentCBs:
           if not cb(data.sock):
             # Callback wants to be called again.
-            newReadCBs.add(cb)
-        data.readCBs = newReadCBs
+            data.readCBs.add(cb)
       
       if EvWrite in info.events:
-        var newWriteCBs: seq[TCallback] = @[]
-        for cb in data.writeCBs:
+        let currentCBs = data.writeCBs
+        data.writeCBs = @[]
+        for cb in currentCBs:
           if not cb(data.sock):
             # Callback wants to be called again.
-            newWriteCBs.add(cb)
-        data.writeCBs = newWriteCBs
+            data.writeCBs.add(cb)
   
       var newEvents: set[TEvent]
       if data.readCBs.len != 0: newEvents = {EvRead}
@@ -615,7 +616,6 @@ else:
           retFuture.complete(0)
     addWrite(p, socket, cb)
     return retFuture
-        
 
   proc acceptAddr*(p: PDispatcher, socket: TSocketHandle): 
       PFuture[tuple[address: string, client: TSocketHandle]] =
@@ -854,7 +854,7 @@ when isMainModule:
   sock.setBlocking false
 
 
-  when false:
+  when true:
     # Await tests
     proc main(p: PDispatcher): PFuture[int] {.async.} =
       discard await p.connect(sock, "irc.freenode.net", TPort(6667))
@@ -880,7 +880,7 @@ when isMainModule:
     
 
   else:
-    when false:
+    when true:
 
       var f = p.connect(sock, "irc.freenode.org", TPort(6667))
       f.callback =
@@ -919,4 +919,4 @@ when isMainModule:
 
   
 
-  
\ No newline at end of file
+  
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
index 6482a01a6..e086ee3ab 100644
--- a/lib/pure/selectors.nim
+++ b/lib/pure/selectors.nim
@@ -10,11 +10,13 @@
 # TODO: Docs.
 
 import tables, os, unsigned, hashes
+import sockets2
 
 when defined(linux): import posix, epoll
 elif defined(windows): import winlean
 
 proc hash*(x: TSocketHandle): THash {.borrow.}
+proc `$`*(x: TSocketHandle): string {.borrow.}
 
 type
   TEvent* = enum
@@ -31,7 +33,7 @@ when defined(linux) or defined(nimdoc):
   type
     PSelector* = ref object
       epollFD: cint
-      events: array[64, ptr epoll_event]
+      events: array[64, epoll_event]
       fds: TTable[TSocketHandle, PSelectorKey]
   
   proc createEventStruct(events: set[TEvent], fd: TSocketHandle): epoll_event =
@@ -66,17 +68,25 @@ when defined(linux) or defined(nimdoc):
     var event = createEventStruct(events, fd)
     
     s.fds[fd].events = events
-    echo("About to update")
     if epoll_ctl(s.epollFD, EPOLL_CTL_MOD, fd, addr(event)) != 0:
+      if OSLastError().cint == ENOENT:
+        # Socket has been closed. Epoll automatically removes disconnected
+        # sockets.
+        s.fds.del(fd)
+        osError("Socket has been disconnected")
+        
       OSError(OSLastError())
-    echo("finished updating")
     result = s.fds[fd]
   
   proc unregister*(s: PSelector, fd: TSocketHandle): PSelectorKey {.discardable.} =
     if not s.fds.hasKey(fd):
       raise newException(EInvalidValue, "File descriptor not found.")
     if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fd, nil) != 0:
-      OSError(OSLastError())
+      if osLastError().cint == ENOENT:
+        # Socket has been closed. Epoll automatically removes disconnected
+        # sockets so its already been removed.
+      else:
+        OSError(OSLastError())
     result = s.fds[fd]
     s.fds.del(fd)
 
@@ -92,21 +102,21 @@ when defined(linux) or defined(nimdoc):
     ## on the ``fd``.
     result = @[]
     
-    let evNum = epoll_wait(s.epollFD, s.events[0], 64.cint, timeout.cint)
+    let evNum = epoll_wait(s.epollFD, addr s.events[0], 64.cint, timeout.cint)
     if evNum < 0: OSError(OSLastError())
     if evNum == 0: return @[]
     for i in 0 .. <evNum:
       var evSet: set[TEvent] = {}
       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[s.events[i].data.fd.TSocketHandle]
+      assert selectorKey != nil
       result.add((selectorKey, evSet))
   
   proc newSelector*(): PSelector =
     new result
     result.epollFD = epoll_create(64)
-    result.events = cast[array[64, ptr epoll_event]](alloc0(sizeof(epoll_event)*64))
+    result.events = cast[array[64, epoll_event]](alloc0(sizeof(epoll_event)*64))
     result.fds = initTable[TSocketHandle, PSelectorKey]()
     if result.epollFD < 0:
       OSError(OSLastError())
@@ -247,4 +257,4 @@ when isMainModule:
   
   
   
-  
\ No newline at end of file
+  
diff --git a/lib/pure/sockets2.nim b/lib/pure/sockets2.nim
index 3542a0694..290f414b4 100644
--- a/lib/pure/sockets2.nim
+++ b/lib/pure/sockets2.nim
@@ -24,6 +24,10 @@ else:
 export TSocketHandle, TSockaddr_in, TAddrinfo, INADDR_ANY, TSockAddr, TSockLen,
   inet_ntoa, recv, `==`, connect, send, accept
 
+export
+  SO_ERROR,
+  SOL_SOCKET
+
 type
   
   TPort* = distinct uint16  ## port type
@@ -208,6 +212,24 @@ proc htons*(x: int16): int16 =
   ## order, this is a no-op; otherwise, it performs a 2-byte swap operation.
   result = sockets2.ntohs(x)
 
+proc getSockOptInt*(socket: TSocketHandle, level, optname: int): int {.
+  tags: [FReadIO].} = 
+  ## getsockopt for integer options.
+  var res: cint
+  var size = sizeof(res).TSocklen
+  if getsockopt(socket, cint(level), cint(optname), 
+                addr(res), addr(size)) < 0'i32:
+    osError(osLastError())
+  result = int(res)
+
+proc setSockOptInt*(socket: TSocketHandle, level, optname, optval: int) {.
+  tags: [FWriteIO].} =
+  ## setsockopt for integer options.
+  var value = cint(optval)
+  if setsockopt(socket, cint(level), cint(optname), addr(value),  
+                sizeof(value).TSocklen) < 0'i32:
+    osError(osLastError())
+
 when defined(Windows):
   var wsa: TWSADATA
   if WSAStartup(0x0101'i16, addr wsa) != 0: OSError(OSLastError())
diff --git a/lib/system.nim b/lib/system.nim
index 171c7b6b8..24ad50f97 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1164,13 +1164,13 @@ when not defined(nimrodVM):
       ## from it before writing to it is undefined behaviour!
       ## The allocated memory belongs to its allocating thread!
       ## Use `allocShared` to allocate from a shared heap.
-    proc alloc*(T: typedesc, size = 1): ptr T {.inline.} =
+    proc createU*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
       ## allocates a new memory block with at least ``T.sizeof * size``
-      ## bytes. The block has to be freed with ``realloc(block, 0)`` or
-      ## ``dealloc(block)``. The block is not initialized, so reading
+      ## bytes. The block has to be freed with ``resize(block, 0)`` or
+      ## ``free(block)``. The block is not initialized, so reading
       ## from it before writing to it is undefined behaviour!
       ## The allocated memory belongs to its allocating thread!
-      ## Use `allocShared` to allocate from a shared heap.
+      ## Use `createSharedU` to allocate from a shared heap.
       cast[ptr T](alloc(T.sizeof * size))
     proc alloc0*(size: int): pointer {.noconv, rtl, tags: [].}
       ## allocates a new memory block with at least ``size`` bytes. The
@@ -1179,13 +1179,13 @@ when not defined(nimrodVM):
       ## containing zero, so it is somewhat safer than ``alloc``.
       ## The allocated memory belongs to its allocating thread!
       ## Use `allocShared0` to allocate from a shared heap.
-    proc alloc0*(T: typedesc, size = 1): ptr T {.inline.} =
+    proc create*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
       ## allocates a new memory block with at least ``T.sizeof * size``
-      ## bytes. The block has to be freed with ``realloc(block, 0)`` or
-      ## ``dealloc(block)``. The block is initialized with all bytes
-      ## containing zero, so it is somewhat safer than ``alloc``.
+      ## bytes. The block has to be freed with ``resize(block, 0)`` or
+      ## ``free(block)``. The block is initialized with all bytes
+      ## containing zero, so it is somewhat safer than ``createU``.
       ## The allocated memory belongs to its allocating thread!
-      ## Use `allocShared0` to allocate from a shared heap.
+      ## Use `createShared` to allocate from a shared heap.
       cast[ptr T](alloc0(T.sizeof * size))
     proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [].}
       ## grows or shrinks a given memory block. If p is **nil** then a new
@@ -1195,14 +1195,14 @@ when not defined(nimrodVM):
       ## be freed with ``dealloc``.
       ## The allocated memory belongs to its allocating thread!
       ## Use `reallocShared` to reallocate from a shared heap.
-    proc reallocType*[T](p: ptr T, newSize: int): ptr T {.inline.} =
+    proc resize*[T](p: ptr T, newSize: Natural): ptr T {.inline.} =
       ## grows or shrinks a given memory block. If p is **nil** then a new
       ## memory block is returned. In either way the block has at least
       ## ``T.sizeof * newSize`` bytes. If ``newSize == 0`` and p is not
-      ## **nil** ``realloc`` calls ``dealloc(p)``. In other cases the block
-      ## has to be freed with ``dealloc``. The allocated memory belongs to
+      ## **nil** ``resize`` calls ``free(p)``. In other cases the block
+      ## has to be freed with ``free``. The allocated memory belongs to
       ## its allocating thread!
-      ## Use `reallocShared` to reallocate from a shared heap.
+      ## Use `resizeShared` to reallocate from a shared heap.
       cast[ptr T](realloc(p, T.sizeof * newSize))
     proc dealloc*(p: pointer) {.noconv, rtl, tags: [].}
       ## frees the memory allocated with ``alloc``, ``alloc0`` or
@@ -1212,16 +1212,18 @@ when not defined(nimrodVM):
       ## or other memory may be corrupted. 
       ## The freed memory must belong to its allocating thread!
       ## Use `deallocShared` to deallocate from a shared heap.
+    proc free*[T](p: ptr T) {.inline.} =
+      dealloc(p)
     proc allocShared*(size: int): pointer {.noconv, rtl.}
       ## allocates a new memory block on the shared heap with at
       ## least ``size`` bytes. The block has to be freed with
       ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
       ## is not initialized, so reading from it before writing to it is 
       ## undefined behaviour!
-    proc allocShared*(T: typedesc, size: int): ptr T {.inline.} =
+    proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
       ## allocates a new memory block on the shared heap with at
       ## least ``T.sizeof * size`` bytes. The block has to be freed with
-      ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
+      ## ``resizeShared(block, 0)`` or ``freeShared(block)``. The block
       ## is not initialized, so reading from it before writing to it is 
       ## undefined behaviour!
       cast[ptr T](allocShared(T.sizeof * size))
@@ -1231,25 +1233,25 @@ when not defined(nimrodVM):
       ## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
       ## The block is initialized with all bytes
       ## containing zero, so it is somewhat safer than ``allocShared``.
-    proc allocShared0*(T: typedesc, size: int): ptr T {.inline.} =
+    proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
       ## allocates a new memory block on the shared heap with at 
       ## least ``T.sizeof * size`` bytes. The block has to be freed with
-      ## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
+      ## ``resizeShared(block, 0)`` or ``freeShared(block)``.
       ## The block is initialized with all bytes
-      ## containing zero, so it is somewhat safer than ``allocShared``.
-      cast[ptr T](allocShared(T.sizeof * size))
+      ## containing zero, so it is somewhat safer than ``createSharedU``.
+      cast[ptr T](allocShared0(T.sizeof * size))
     proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl.}
       ## grows or shrinks a given memory block on the heap. If p is **nil**
       ## then a new memory block is returned. In either way the block has at
       ## least ``newSize`` bytes. If ``newSize == 0`` and p is not **nil**
       ## ``reallocShared`` calls ``deallocShared(p)``. In other cases the
       ## block has to be freed with ``deallocShared``.
-    proc reallocSharedType*[T](p: ptr T, newSize: int): ptr T {.inline.} =
+    proc resizeShared*[T](p: ptr T, newSize: Natural): ptr T {.inline.} =
       ## grows or shrinks a given memory block on the heap. If p is **nil**
       ## then a new memory block is returned. In either way the block has at
       ## least ``T.sizeof * newSize`` bytes. If ``newSize == 0`` and p is
-      ## not **nil** ``reallocShared`` calls ``deallocShared(p)``. In other
-      ## cases the block has to be freed with ``deallocShared``.
+      ## not **nil** ``resizeShared`` calls ``freeShared(p)``. In other
+      ## cases the block has to be freed with ``freeShared``.
       cast[ptr T](reallocShared(p, T.sizeof * newSize))
     proc deallocShared*(p: pointer) {.noconv, rtl.}
       ## frees the memory allocated with ``allocShared``, ``allocShared0`` or
@@ -1257,6 +1259,13 @@ when not defined(nimrodVM):
       ## free the memory a leak occurs; if one tries to access freed
       ## memory (or just freeing it twice!) a core dump may happen
       ## or other memory may be corrupted.
+    proc freeShared*[T](p: ptr T) {.inline.} =
+      ## frees the memory allocated with ``createShared``, ``createSharedU`` or
+      ## ``resizeShared``. This procedure is dangerous! If one forgets to
+      ## free the memory a leak occurs; if one tries to access freed
+      ## memory (or just freeing it twice!) a core dump may happen
+      ## or other memory may be corrupted.
+      deallocShared(p)
 
 proc swap*[T](a, b: var T) {.magic: "Swap", noSideEffect.}
   ## swaps the values `a` and `b`. This is often more efficient than
diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim
index bde5bf8c8..9e5d270c3 100644
--- a/tests/async/tasyncawait.nim
+++ b/tests/async/tasyncawait.nim
@@ -15,16 +15,24 @@ const
 var clientCount = 0
 
 proc sendMessages(disp: PDispatcher, client: TSocketHandle): PFuture[int] {.async.} =
+  echo("entering sendMessages")
   for i in 0 .. <messagesToSend:
-    discard await disp.send(client, "Message " & $i & "\c\L") 
+    discard await disp.send(client, "Message " & $i & "\c\L")
+  echo("returning sendMessages")
 
 proc launchSwarm(disp: PDispatcher, port: TPort): PFuture[int] {.async.} =
   for i in 0 .. <swarmSize:
     var sock = socket()
+    # TODO: We may need to explicitly register and unregister the fd.
+    # This is because when the socket is closed, selectors is not aware
+    # that it has been closed. While epoll is. Perhaps we should just unregister
+    # in close()?
+    echo(sock.cint)
     #disp.register(sock)
     discard await disp.connect(sock, "localhost", port)
     when true:
       discard await sendMessages(disp, sock)
+      echo("Calling close")
       sock.close()
     else:
       # Issue #932: https://github.com/Araq/Nimrod/issues/932
diff --git a/tests/generics/tgenericshardcases.nim b/tests/generics/tgenericshardcases.nim
index 2ef63bc20..e3b805db6 100644
--- a/tests/generics/tgenericshardcases.nim
+++ b/tests/generics/tgenericshardcases.nim
@@ -14,7 +14,8 @@ macro selectType(a, b: typedesc): typedesc =
 type
   Foo[T] = object
     data1: array[T.high, int]
-    data2: array[typeNameLen(T), float] # data3: array[0..T.typeNameLen, selectType(float, int)]
+    data2: array[typeNameLen(T), float]
+    data3: array[0..T.typeNameLen, selectType(float, int)]
 
   MyEnum = enum A, B, C, D
 
@@ -27,10 +28,15 @@ echo high(f1.data2) # (MyEnum.len = 6) - 1 == 5
 echo high(f2.data1) # 127 - 1 == 126
 echo high(f2.data2) # int8.len - 1 == 3
 
-#static:
-# assert high(f1.data1) == ord(D)
-# assert high(f1.data2) == 6 # length of MyEnum
+static:
+  assert high(f1.data1) == ord(C)
+  assert high(f1.data2) == 5 # length of MyEnum minus one, because we used T.high
 
-# assert high(f2.data1) == 127
-# assert high(f2.data2) == 4 # length of int8
+  assert high(f2.data1) == 126
+  assert high(f2.data2) == 3 
+
+  assert high(f1.data3) == 6 # length of MyEnum
+  assert high(f2.data3) == 4 # length of int8
+
+  assert f2.data3[0] is float
 
diff --git a/tests/iter/tchainediterators.nim b/tests/iter/tchainediterators.nim
new file mode 100644
index 000000000..18d096761
--- /dev/null
+++ b/tests/iter/tchainediterators.nim
@@ -0,0 +1,38 @@
+discard """
+  output: '''16
+32
+48
+64
+128
+192
+'''
+"""
+
+iterator gaz(it: iterator{.inline.}): type(it) =
+  for x in it:
+    yield x*2
+
+iterator baz(it: iterator{.inline.}) =
+  for x in gaz(it):
+    yield x*2
+
+type T1 = auto
+
+iterator bar(it: iterator: T1{.inline.}): T1 =
+  for x in baz(it):
+    yield x*2
+
+iterator foo[T](x: iterator: T{.inline.}): T =
+  for e in bar(x):
+    yield e*2
+
+var s = @[1, 2, 3]
+
+# pass an interator several levels deep:
+for x in s.items.foo:
+  echo x
+
+# use some complex iterator as an input for another one:
+for x in s.items.baz.foo:
+  echo x
+
diff --git a/tests/iter/titerable.nim b/tests/iter/titerable.nim
new file mode 100644
index 000000000..3ec79f68d
--- /dev/null
+++ b/tests/iter/titerable.nim
@@ -0,0 +1,26 @@
+discard """
+  output: '''2
+4
+6
+4
+8
+12
+'''
+"""
+
+iterator map[T, U](s: iterator:T{.inline.}, f: proc(x: T): U): U =
+  for e in s: yield f(e)
+
+template toSeq(s: expr): expr =
+  var res = newSeq[type(s)](0)
+  for e in s: res.add(e)
+  res
+
+var s1 = @[1, 2, 3]
+for x in map(s1.items, proc (a:int): int = a*2):
+  echo x
+
+var s2 = toSeq(map(s1.items, proc (a:int): int = a*4))
+for x in s2:
+  echo x
+
diff --git a/tests/metatype/tstaticparams.nim b/tests/metatype/tstaticparams.nim
index b1377443b..e76dae23c 100644
--- a/tests/metatype/tstaticparams.nim
+++ b/tests/metatype/tstaticparams.nim
@@ -1,6 +1,6 @@
 discard """
   file: "tstaticparams.nim"
-  output: "abracadabra\ntest\n3"
+  output: "abracadabra\ntest\n3\n15\4"
 """
 
 type 
@@ -11,8 +11,8 @@ type
     data: array[I, T]
 
   TA1[T; I: static[int]] = array[I, T]
-  # TA2[T; I: static[int]] = array[0..I, T]
-  # TA3[T; I: static[int]] = array[I-1, T]
+  TA2[T; I: static[int]] = array[0..I, T]
+  TA3[T; I: static[int]] = array[I-1, T]
 
 proc takeFoo(x: TFoo) =
   echo "abracadabra"
@@ -26,6 +26,22 @@ echo high(y.data)
 
 var
   t1: TA1[float, 1]
-  # t2: TA2[string, 4]
-  # t3: TA3[int, 10]
+  t2: TA2[string, 4]
+  t3: TA3[int, 10]
 
+# example from the manual:
+type
+  Matrix[M,N: static[int]; T] = array[0..(M*N - 1), T]
+    # Note how `Number` is just a type constraint here, while
+    # `static[int]` requires us to supply a compile-time int value
+
+  AffineTransform2D[T] = Matrix[3, 3, T]
+  AffineTransform3D[T] = Matrix[4, 4, T]
+
+var m: AffineTransform3D[float]
+echo high(m)
+
+proc getRows(mtx: Matrix): int =
+  result = mtx.M
+
+echo getRows(m)
diff --git a/tests/overload/tissue966.nim b/tests/overload/tissue966.nim
new file mode 100644
index 000000000..53ec2f108
--- /dev/null
+++ b/tests/overload/tissue966.nim
@@ -0,0 +1,12 @@
+discard """
+  msg: 'type mismatch: got (PTest)'
+"""
+
+type
+  PTest = ref object
+
+proc test(x: PTest, y: int) = nil
+
+var buf: PTest
+buf.test()
+
diff --git a/tests/static/tstaticparammacro.nim b/tests/static/tstaticparammacro.nim
new file mode 100644
index 000000000..7fb9e2014
--- /dev/null
+++ b/tests/static/tstaticparammacro.nim
@@ -0,0 +1,52 @@
+discard """
+  msg: '''letters
+aa
+bb
+numbers
+11
+22
+AST a 
+[(11, 22), (33, 44)]
+AST b 
+(e: [55, 66], f: [77, 88])
+55
+'''
+"""
+
+import macros
+
+type
+  TConfig = tuple
+    letters: seq[string]
+    numbers:seq[int]
+
+const data: Tconfig = (@["aa", "bb"], @[11, 22])
+
+macro mymacro(data: static[TConfig]): stmt =
+  echo "letters"
+  for s in items(data.letters):
+    echo s
+  echo "numbers"
+  for n in items(data.numbers):
+    echo n
+
+mymacro(data)
+
+type
+  Ta = seq[tuple[c:int, d:int]]
+  Tb = tuple[e:seq[int], f:seq[int]]
+
+const
+  a : Ta = @[(11, 22), (33, 44)]
+  b : Tb = (@[55,66], @[77, 88])
+
+macro mA(data: static[Ta]): stmt =
+  echo "AST a \n", repr(data)
+
+macro mB(data: static[Tb]): stmt =
+  echo "AST b \n", repr(data)
+  echo data.e[0]
+
+mA(a)
+mB(b)
+
diff --git a/tests/system/alloc.nim b/tests/system/alloc.nim
index 665b448ac..7abefec2a 100644
--- a/tests/system/alloc.nim
+++ b/tests/system/alloc.nim
@@ -2,44 +2,51 @@ var x: ptr int
 
 x = cast[ptr int](alloc(7))
 assert x != nil
-
-x = alloc(int, 3)
+x = cast[ptr int](x.realloc(2))
 assert x != nil
 x.dealloc()
 
-x = alloc0(int, 4)
+x = createU(int, 3)
+assert x != nil
+x.free()
+
+x = create(int, 4)
 assert cast[ptr array[4, int]](x)[0] == 0
 assert cast[ptr array[4, int]](x)[1] == 0
 assert cast[ptr array[4, int]](x)[2] == 0
 assert cast[ptr array[4, int]](x)[3] == 0
 
-x = cast[ptr int](x.realloc(2))
-assert x != nil
-
-x = x.reallocType(4)
+x = x.resize(4)
 assert x != nil
-x.dealloc()
+x.free()
 
 x = cast[ptr int](allocShared(100))
 assert x != nil
 deallocShared(x)
 
-x = allocShared(int, 3)
+x = createSharedU(int, 3)
 assert x != nil
-x.deallocShared()
+x.freeShared()
 
-x = allocShared0(int, 3)
+x = createShared(int, 3)
 assert x != nil
 assert cast[ptr array[3, int]](x)[0] == 0
 assert cast[ptr array[3, int]](x)[1] == 0
 assert cast[ptr array[3, int]](x)[2] == 0
 
-x = cast[ptr int](reallocShared(x, 2))
 assert x != nil
+x = cast[ptr int](x.resizeShared(2))
+assert x != nil
+x.freeShared()
 
-x = reallocType(x, 12)
+x = create(int, 10)
 assert x != nil
+x = x.resize(12)
+assert x != nil
+x.dealloc()
 
-x = reallocSharedType(x, 1)
+x = createShared(int, 1)
+assert x != nil
+x = x.resizeShared(1)
 assert x != nil
-x.deallocShared()
+x.freeShared()
diff --git a/tests/template/tissue909.nim b/tests/template/tissue909.nim
new file mode 100644
index 000000000..5b57a3558
--- /dev/null
+++ b/tests/template/tissue909.nim
@@ -0,0 +1,16 @@
+import macros
+
+template baz() =
+  proc bar() =
+    var x = 5
+    iterator foo(): int {.closure.} =
+      echo x
+    var y = foo
+    discard y()
+
+macro test(): stmt =
+  result = getAst(baz())
+  echo(treeRepr(result))
+
+test()
+bar()
diff --git a/tests/testament/htmlgen.nim b/tests/testament/htmlgen.nim
index 74d8811b8..89d56c693 100644
--- a/tests/testament/htmlgen.nim
+++ b/tests/testament/htmlgen.nim
@@ -174,6 +174,10 @@ proc generateJson*(filename: string, commit: int) =
                 on A.name = B.name and A.category = B.category
                 where A.[commit] = ? and B.[commit] = ? and A.machine = ?
                    and A.result != B.result"""
+    selResults = """select 
+                      name, category, target, action, result, expected, given 
+                    from TestResult
+                    where [commit] = ?"""
   var db = open(connection="testament.db", user="testament", password="",
                 database="testament")
   let lastCommit = db.getCommit(commit)
@@ -189,6 +193,20 @@ proc generateJson*(filename: string, commit: int) =
 
   outfile.writeln("""{"total": $#, "passed": $#, "skipped": $#""" % data)
 
+  let results = newJArray()
+  for row in db.rows(sql(selResults), lastCommit):
+    var obj = newJObject()
+    obj["name"] = %row[0]
+    obj["category"] = %row[1]
+    obj["target"] = %row[2]
+    obj["action"] = %row[3]
+    obj["result"] = %row[4]
+    obj["expected"] = %row[5]
+    obj["given"] = %row[6]
+    results.add(obj)
+  outfile.writeln(""", "results": """)
+  outfile.write(results.pretty)
+
   if not previousCommit.isNil:
     let diff = newJArray()
 
diff --git a/tests/vm/tstaticprintseq.nim b/tests/vm/tstaticprintseq.nim
index 99a56d161..4575f3af1 100644
--- a/tests/vm/tstaticprintseq.nim
+++ b/tests/vm/tstaticprintseq.nim
@@ -4,7 +4,17 @@ discard """
 3
 1
 2
-3'''
+3
+1
+2
+3
+1
+2
+3
+aa
+bb
+aa
+bb'''
 """
 
 const s = @[1,2,3]
@@ -19,3 +29,27 @@ static:
   for e in s:
     echo e
 
+macro bar(x: static[seq[int]]): stmt =
+  for e in x:
+    echo e
+
+bar s
+bar(@[1, 2, 3])
+
+type
+  TData = tuple
+    letters: seq[string]
+    numbers: seq[int]
+
+const data: TData = (@["aa", "bb"], @[11, 22])
+
+static:
+  var m = data
+  for x in m.letters:
+    echo x
+
+macro ff(d: static[TData]): stmt =
+  for x in d.letters:
+    echo x
+
+ff(data)