summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2017-05-04 16:02:50 +0200
committerAndreas Rumpf <rumpf_a@web.de>2017-05-04 16:02:50 +0200
commit764cc0217735454c166cb7dd490db58f5fa6fe26 (patch)
tree63633b39ae24815e8b677ccbc9bac2cb01c39d3b
parentafa80092d378a6dbc116c0aa3ed3964fd8c599d6 (diff)
parentc1aa973758a60d7ef0e698c94861b74132612de5 (diff)
downloadNim-764cc0217735454c166cb7dd490db58f5fa6fe26.tar.gz
Merge branch 'devel' into araq
-rw-r--r--compiler/cgen.nim7
-rw-r--r--compiler/jsgen.nim36
-rw-r--r--compiler/lowerings.nim68
-rw-r--r--compiler/nimblecmd.nim41
-rw-r--r--compiler/parser.nim5
-rw-r--r--compiler/semexprs.nim6
-rw-r--r--compiler/sempass2.nim2
-rw-r--r--compiler/trees.nim2
-rw-r--r--config/nimdoc.cfg2
-rw-r--r--doc/intern.txt2
-rw-r--r--koch.nim4
-rw-r--r--lib/posix/posix.nim9
-rw-r--r--lib/posix/posix_linux_amd64.nim9
-rw-r--r--lib/posix/posix_other.nim15
-rw-r--r--lib/pure/asyncdispatch.nim170
-rw-r--r--lib/pure/asyncnet.nim11
-rw-r--r--lib/pure/base64.nim41
-rw-r--r--lib/pure/collections/tables.nim4
-rw-r--r--lib/pure/cookies.nim4
-rw-r--r--lib/pure/httpclient.nim49
-rw-r--r--lib/pure/includes/asynccommon.nim201
-rw-r--r--lib/pure/json.nim51
-rw-r--r--lib/pure/nativesockets.nim63
-rw-r--r--lib/pure/net.nim61
-rw-r--r--lib/pure/oids.nim3
-rw-r--r--lib/pure/ospaths.nim2
-rw-r--r--lib/pure/osproc.nim42
-rw-r--r--lib/pure/uri.nim21
-rw-r--r--lib/system.nim6
-rw-r--r--lib/system/jssys.nim2
-rw-r--r--lib/upcoming/asyncdispatch.nim171
-rw-r--r--lib/windows/winlean.nim3
-rw-r--r--readme.md3
-rw-r--r--tests/async/tasyncdial.nim53
-rw-r--r--tests/osproc/texitsignal.nim36
-rw-r--r--tests/parser/twrongcmdsyntax.nim6
-rw-r--r--tests/stdlib/thttpclient.nim40
-rw-r--r--tests/stdlib/tjsonmacro.nim50
-rw-r--r--tests/stdlib/tnetdial.nim60
-rw-r--r--tests/tuples/tunpack_asgn.nim2
-rw-r--r--tests/tuples/tuple_subscript.nim40
-rw-r--r--web/news/e031_version_0_16_2.rst10
42 files changed, 960 insertions, 453 deletions
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index bad346298..c9b047a49 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -1324,8 +1324,11 @@ proc shouldRecompile(code: Rope, cfile: Cfile): bool =
   if optForceFullMake notin gGlobalOptions:
     if not equalsFile(code, cfile.cname):
       if isDefined("nimdiff"):
-        copyFile(cfile.cname, cfile.cname & ".backup")
-        echo "diff ", cfile.cname, ".backup ", cfile.cname
+        if fileExists(cfile.cname):
+          copyFile(cfile.cname, cfile.cname & ".backup")
+          echo "diff ", cfile.cname, ".backup ", cfile.cname
+        else:
+          echo "new file ", cfile.cname
       writeRope(code, cfile.cname)
       return
     if existsFile(cfile.obj) and os.fileNewer(cfile.obj, cfile.cname):
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 0016a8492..eb3fb9f47 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -434,22 +434,23 @@ proc binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
 
 proc unsignedTrimmerJS(size: BiggestInt): Rope =
   case size
-    of 1: rope"& 0xff"
-    of 2: rope"& 0xffff"
-    of 4: rope">>> 0"
-    else: rope""
+  of 1: rope"& 0xff"
+  of 2: rope"& 0xffff"
+  of 4: rope">>> 0"
+  else: rope""
 
 proc unsignedTrimmerPHP(size: BiggestInt): Rope =
   case size
-    of 1: rope"& 0xff"
-    of 2: rope"& 0xffff"
-    of 4: rope"& 0xffffffff"
-    else: rope""
+  of 1: rope"& 0xff"
+  of 2: rope"& 0xffff"
+  of 4: rope"& 0xffffffff"
+  else: rope""
 
 template unsignedTrimmer(size: BiggestInt): Rope =
   size.unsignedTrimmerJS | size.unsignedTrimmerPHP
 
-proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string, reassign: bool = false) =
+proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string,
+                    reassign = false) =
   var x, y: TCompRes
   gen(p, n.sons[1], x)
   gen(p, n.sons[2], y)
@@ -1633,11 +1634,11 @@ proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope =
 
   gen(p, n.sons[1], a)
   if magic == "reprAny":
-    # the pointer argument in reprAny is expandend to 
+    # the pointer argument in reprAny is expandend to
     # (pointedto, pointer), so we need to fill it
     if a.address.isNil:
       add(r.res, a.res)
-      add(r.res, ", null") 
+      add(r.res, ", null")
     else:
       add(r.res, "$1, $2" % [a.address, a.res])
   else:
@@ -1670,7 +1671,7 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
     genReprAux(p, n, r, "reprSet", genTypeInfo(p, t))
   of tyEmpty, tyVoid:
     localError(n.info, "'repr' doesn't support 'void' type")
-  of tyPointer: 
+  of tyPointer:
     genReprAux(p, n, r, "reprPointer")
   of tyOpenArray, tyVarargs:
     genReprAux(p, n, r, "reprJSONStringify")
@@ -1863,8 +1864,8 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
 proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) =
   var
     a, b: TCompRes
-  useMagic(p, "SetConstr")
-  r.res = rope("SetConstr(")
+  useMagic(p, "setConstr")
+  r.res = rope("setConstr(")
   r.kind = resExpr
   for i in countup(0, sonsLen(n) - 1):
     if i > 0: add(r.res, ", ")
@@ -1877,6 +1878,12 @@ proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) =
       gen(p, it, a)
       add(r.res, a.res)
   add(r.res, ")")
+  # emit better code for constant sets:
+  if p.target == targetJS and isDeepConstExpr(n):
+    inc(p.g.unique)
+    let tmp = rope("ConstSet") & rope(p.g.unique)
+    addf(p.g.constants, "var $1 = $2;$n", [tmp, r.res])
+    r.res = tmp
 
 proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
@@ -2128,6 +2135,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
     else: r.res = rope(f.toStrMaxPrecision)
     r.kind = resExpr
   of nkCallKinds:
+    if isEmptyType(n.typ): genLineDir(p, n)
     if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone):
       genMagic(p, n, r)
     elif n.sons[0].kind == nkSym and sfInfixCall in n.sons[0].sym.flags and
diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim
index 245cc5f61..4bd54603d 100644
--- a/compiler/lowerings.nim
+++ b/compiler/lowerings.nim
@@ -74,9 +74,9 @@ proc lowerTupleUnpackingForAsgn*(n: PNode; owner: PSym): PNode =
   let value = n.lastSon
   result = newNodeI(nkStmtList, n.info)
 
-  var temp = newSym(skTemp, getIdent(genPrefix), owner, value.info)
+  var temp = newSym(skLet, getIdent("_"), owner, value.info)
   var v = newNodeI(nkLetSection, value.info)
-  let tempAsNode = newIdentNode(getIdent(genPrefix & $temp.id), value.info)
+  let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info)
 
   var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
   vpart.sons[0] = tempAsNode
@@ -115,7 +115,7 @@ proc createObj*(owner: PSym, info: TLineInfo): PType =
   incl result.flags, tfFinal
   result.n = newNodeI(nkRecList, info)
   when true:
-    let s = newSym(skType, getIdent("Env_" & info.toFilename & "_" & $info.line),
+    let s = newSym(skType, getIdent("Env_" & info.toFilename),
                    owner, info)
     incl s.flags, sfAnon
     s.typ = result
@@ -137,10 +137,32 @@ proc rawIndirectAccess*(a: PNode; field: PSym; info: TLineInfo): PNode =
   addSon(result, newSymNode(field))
   result.typ = field.typ
 
+proc lookupInRecord(n: PNode, id: int): PSym =
+  result = nil
+  case n.kind
+  of nkRecList:
+    for i in countup(0, sonsLen(n) - 1):
+      result = lookupInRecord(n.sons[i], id)
+      if result != nil: return
+  of nkRecCase:
+    if n.sons[0].kind != nkSym: return
+    result = lookupInRecord(n.sons[0], id)
+    if result != nil: return
+    for i in countup(1, sonsLen(n) - 1):
+      case n.sons[i].kind
+      of nkOfBranch, nkElse:
+        result = lookupInRecord(lastSon(n.sons[i]), id)
+        if result != nil: return
+      else: discard
+  of nkSym:
+    if n.sym.id == -abs(id): result = n.sym
+  else: discard
+
 proc addField*(obj: PType; s: PSym) =
   # because of 'gensym' support, we have to mangle the name with its ID.
   # This is hacky but the clean solution is much more complex than it looks.
-  var field = newSym(skField, getIdent(s.name.s & $s.id), s.owner, s.info)
+  var field = newSym(skField, getIdent(s.name.s & $obj.n.len), s.owner, s.info)
+  field.id = -s.id
   let t = skipIntLit(s.typ)
   field.typ = t
   assert t.kind != tyStmt
@@ -148,9 +170,9 @@ proc addField*(obj: PType; s: PSym) =
   addSon(obj.n, newSymNode(field))
 
 proc addUniqueField*(obj: PType; s: PSym) =
-  let fieldName = getIdent(s.name.s & $s.id)
-  if lookupInRecord(obj.n, fieldName) == nil:
-    var field = newSym(skField, fieldName, s.owner, s.info)
+  if lookupInRecord(obj.n, s.id) == nil:
+    var field = newSym(skField, getIdent(s.name.s & $obj.n.len), s.owner, s.info)
+    field.id = -s.id
     let t = skipIntLit(s.typ)
     field.typ = t
     assert t.kind != tyStmt
@@ -159,13 +181,36 @@ proc addUniqueField*(obj: PType; s: PSym) =
 
 proc newDotExpr(obj, b: PSym): PNode =
   result = newNodeI(nkDotExpr, obj.info)
-  let field = getSymFromList(obj.typ.n, getIdent(b.name.s & $b.id))
+  let field = lookupInRecord(obj.typ.n, b.id)
   assert field != nil, b.name.s
   addSon(result, newSymNode(obj))
   addSon(result, newSymNode(field))
   result.typ = field.typ
 
-proc indirectAccess*(a: PNode, b: string, info: TLineInfo): PNode =
+proc indirectAccess*(a: PNode, b: int, info: TLineInfo): PNode =
+  # returns a[].b as a node
+  var deref = newNodeI(nkHiddenDeref, info)
+  deref.typ = a.typ.skipTypes(abstractInst).sons[0]
+  var t = deref.typ.skipTypes(abstractInst)
+  var field: PSym
+  while true:
+    assert t.kind == tyObject
+    field = lookupInRecord(t.n, b)
+    if field != nil: break
+    t = t.sons[0]
+    if t == nil: break
+    t = t.skipTypes(skipPtrs)
+  #if field == nil:
+  #  echo "FIELD ", b
+  #  debug deref.typ
+  internalAssert field != nil
+  addSon(deref, a)
+  result = newNodeI(nkDotExpr, info)
+  addSon(result, deref)
+  addSon(result, newSymNode(field))
+  result.typ = field.typ
+
+proc indirectAccess(a: PNode, b: string, info: TLineInfo): PNode =
   # returns a[].b as a node
   var deref = newNodeI(nkHiddenDeref, info)
   deref.typ = a.typ.skipTypes(abstractInst).sons[0]
@@ -191,11 +236,10 @@ proc indirectAccess*(a: PNode, b: string, info: TLineInfo): PNode =
 
 proc getFieldFromObj*(t: PType; v: PSym): PSym =
   assert v.kind != skField
-  let fieldName = getIdent(v.name.s & $v.id)
   var t = t
   while true:
     assert t.kind == tyObject
-    result = getSymFromList(t.n, fieldName)
+    result = lookupInRecord(t.n, v.id)
     if result != nil: break
     t = t.sons[0]
     if t == nil: break
@@ -203,7 +247,7 @@ proc getFieldFromObj*(t: PType; v: PSym): PSym =
 
 proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode =
   # returns a[].b as a node
-  result = indirectAccess(a, b.name.s & $b.id, info)
+  result = indirectAccess(a, b.id, info)
 
 proc indirectAccess*(a, b: PSym, info: TLineInfo): PNode =
   result = indirectAccess(newSymNode(a), b, info)
diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim
index e6466fc24..5e6d843de 100644
--- a/compiler/nimblecmd.nim
+++ b/compiler/nimblecmd.nim
@@ -17,15 +17,17 @@ proc addPath*(path: string, info: TLineInfo) =
 
 proc versionSplitPos(s: string): int =
   result = s.len-2
-  while result > 1 and s[result] in {'0'..'9', '.'}: dec result
+  #while result > 1 and s[result] in {'0'..'9', '.'}: dec result
+  while result > 1 and s[result] != '-': dec result
   if s[result] != '-': result = s.len
 
 const
-  latest = "head"
+  latest = ""
 
 proc `<.`(a, b: string): bool =
   # wether a has a smaller version than b:
-  if a == latest: return false
+  if a == latest: return true
+  elif b == latest: return false
   var i = 0
   var j = 0
   var verA = 0
@@ -33,8 +35,13 @@ proc `<.`(a, b: string): bool =
   while true:
     let ii = parseInt(a, verA, i)
     let jj = parseInt(b, verB, j)
-    # if A has no number left, but B has, B is preferred:  0.8 vs 0.8.3
-    if ii <= 0 or jj <= 0: return jj > 0
+    if ii <= 0 or jj <= 0:
+      # if A has no number and B has but A has no number whatsoever ("#head"),
+      # A is preferred:
+      if ii > 0 and jj <= 0 and j == 0: return true
+      if ii <= 0 and jj > 0 and i == 0: return false
+      # if A has no number left, but B has, B is preferred:  0.8 vs 0.8.3
+      return jj > 0
     if verA < verB: return true
     elif verA > verB: return false
     # else: same version number; continue:
@@ -46,12 +53,9 @@ proc `<.`(a, b: string): bool =
 proc addPackage(packages: StringTableRef, p: string) =
   let x = versionSplitPos(p)
   let name = p.substr(0, x-1)
-  if x < p.len:
-    let version = p.substr(x+1)
-    if packages.getOrDefault(name) <. version:
-      packages[name] = version
-  else:
-    packages[name] = latest
+  let version = if x < p.len: p.substr(x+1) else: ""
+  if packages.getOrDefault(name) <. version:
+    packages[name] = version
 
 iterator chosen(packages: StringTableRef): string =
   for key, val in pairs(packages):
@@ -76,3 +80,18 @@ proc addPathRec(dir: string, info: TLineInfo) =
 proc nimblePath*(path: string, info: TLineInfo) =
   addPathRec(path, info)
   addNimblePath(path, info)
+
+when isMainModule:
+  var rr = newStringTable()
+  addPackage rr, "irc-#head"
+  addPackage rr, "irc-0.1.0"
+  addPackage rr, "irc"
+  addPackage rr, "another"
+  addPackage rr, "another-0.1"
+
+  addPackage rr, "ab-0.1.3"
+  addPackage rr, "ab-0.1"
+  addPackage rr, "justone"
+
+  for p in rr.chosen:
+    echo p
diff --git a/compiler/parser.nim b/compiler/parser.nim
index e9dff25ac..fabe4bcc8 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -1238,10 +1238,7 @@ proc parseExprStmt(p: var TParser): PNode =
         addSon(result, e)
         if p.tok.tokType != tkComma: break
     elif p.tok.indent < 0 and isExprStart(p):
-      if a.kind == nkCommand:
-        result = a
-      else:
-        result = newNode(nkCommand, a.info, @[a])
+      result = newNode(nkCommand, a.info, @[a])
       while true:
         var e = parseExpr(p)
         addSon(result, e)
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 316cf55c8..25f62983d 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1266,7 +1266,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
     result.typ = makeTypeDesc(c, semTypeNode(c, n, nil))
     #result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
   of tyTuple:
-    checkSonsLen(n, 2)
+    if n.len != 2: return nil
     n.sons[0] = makeDeref(n.sons[0])
     c.p.bracketExpr = n.sons[0]
     # [] operator for tuples requires constant expression:
@@ -1276,9 +1276,9 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
       var idx = getOrdValue(n.sons[1])
       if idx >= 0 and idx < sonsLen(arr): n.typ = arr.sons[int(idx)]
       else: localError(n.info, errInvalidIndexValueForTuple)
+      result = n
     else:
-      localError(n.info, errIndexTypesDoNotMatch)
-    result = n
+      result = nil
   else:
     let s = if n.sons[0].kind == nkSym: n.sons[0].sym
             elif n[0].kind in nkSymChoices: n.sons[0][0].sym
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index ce7474966..96bdc6cba 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -517,7 +517,7 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
 proc procVarcheck(n: PNode) =
   if n.kind in nkSymChoices:
     for x in n: procVarCheck(x)
-  elif n.kind == nkSym and n.sym.magic != mNone:
+  elif n.kind == nkSym and n.sym.magic != mNone and n.sym.kind in routineKinds:
     localError(n.info, errXCannotBePassedToProcVar, n.sym.name.s)
 
 proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
diff --git a/compiler/trees.nim b/compiler/trees.nim
index 424fba14c..8f0af89d3 100644
--- a/compiler/trees.nim
+++ b/compiler/trees.nim
@@ -96,7 +96,7 @@ proc isDeepConstExpr*(n: PNode): bool =
     result = true
   of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
     result = isDeepConstExpr(n.sons[1])
-  of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure:
+  of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure, nkRange:
     for i in ord(n.kind == nkObjConstr) .. <n.len:
       if not isDeepConstExpr(n.sons[i]): return false
     if n.typ.isNil: result = true
diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg
index fdc3d2ba0..3e656cb8f 100644
--- a/config/nimdoc.cfg
+++ b/config/nimdoc.cfg
@@ -129,6 +129,8 @@ doc.file = """<?xml version="1.0" encoding="utf-8" ?>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+
 <!-- Favicon -->
 <link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
 
diff --git a/doc/intern.txt b/doc/intern.txt
index d0aaa283a..dadb0eb05 100644
--- a/doc/intern.txt
+++ b/doc/intern.txt
@@ -157,7 +157,7 @@ compilation fails. This exit code tells ``git bisect`` to skip the
 current commit.::
 
   git bisect start bad-commit good-commit
-  git bisect ./koch -r c test-source.nim
+  git bisect run ./koch temp -r c test-source.nim
 
 The compiler's architecture
 ===========================
diff --git a/koch.nim b/koch.nim
index e24367dd5..da99ea264 100644
--- a/koch.nim
+++ b/koch.nim
@@ -178,7 +178,7 @@ proc bundleNimbleExe() =
   bundleNimbleSrc()
   # now compile Nimble and copy it to $nim/bin for the installer.ini
   # to pick it up:
-  nimexec("c dist/nimble/src/nimble.nim")
+  nimexec("c -d:release dist/nimble/src/nimble.nim")
   copyExe("dist/nimble/src/nimble".exe, "bin/nimble".exe)
 
 proc buildNimble(latest: bool) =
@@ -205,7 +205,7 @@ proc buildNimble(latest: bool) =
       else:
         exec("git checkout -f stable")
       exec("git pull")
-  nimexec("c --noNimblePath -p:compiler " & installDir / "src/nimble.nim")
+  nimexec("c --noNimblePath -p:compiler -d:release " & installDir / "src/nimble.nim")
   copyExe(installDir / "src/nimble".exe, "bin/nimble".exe)
 
 proc bundleNimsuggest(buildExe: bool) =
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim
index ab608efc6..02312a4d5 100644
--- a/lib/posix/posix.nim
+++ b/lib/posix/posix.nim
@@ -97,15 +97,6 @@ when not defined(macosx):
     ## Second-granularity time of last status change.
     result = s.st_ctim.tv_sec
 
-proc WIFCONTINUED*(s:cint) : bool {.importc, header: "<sys/wait.h>".}
-  ## True if child has been continued.
-proc WIFEXITED*(s:cint) : bool {.importc, header: "<sys/wait.h>".}
-  ## True if child exited normally.
-proc WIFSIGNALED*(s:cint) : bool {.importc, header: "<sys/wait.h>".}
-  ## True if child exited due to uncaught signal.
-proc WIFSTOPPED*(s:cint) : bool {.importc, header: "<sys/wait.h>".}
-  ## True if child is currently stopped.
-
 when hasAioH:
   proc aio_cancel*(a1: cint, a2: ptr Taiocb): cint {.importc, header: "<aio.h>".}
   proc aio_error*(a1: ptr Taiocb): cint {.importc, header: "<aio.h>".}
diff --git a/lib/posix/posix_linux_amd64.nim b/lib/posix/posix_linux_amd64.nim
index 4948642c1..70f7e710f 100644
--- a/lib/posix/posix_linux_amd64.nim
+++ b/lib/posix/posix_linux_amd64.nim
@@ -602,3 +602,12 @@ var
 include posix_linux_amd64_consts
 
 const POSIX_SPAWN_USEVFORK* = cint(0x40)  # needs _GNU_SOURCE!
+
+# <sys/wait.h>
+proc WEXITSTATUS*(s: cint): cint =  (s and 0xff00) shr 8
+proc WTERMSIG*(s:cint): cint = s and 0x7f
+proc WSTOPSIG*(s:cint): cint = WEXITSTATUS(s)
+proc WIFEXITED*(s:cint) : bool = WTERMSIG(s) == 0
+proc WIFSIGNALED*(s:cint) : bool = (cast[int8]((s and 0x7f) + 1) shr 1) > 0
+proc WIFSTOPPED*(s:cint) : bool = (s and 0xff) == 0x7f
+proc WIFCONTINUED*(s:cint) : bool = s == W_CONTINUED
diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim
index 6e1c33605..b1cc244b7 100644
--- a/lib/posix/posix_other.nim
+++ b/lib/posix/posix_other.nim
@@ -611,3 +611,18 @@ when hasSpawnH:
     # OR'ing of flags:
     const POSIX_SPAWN_USEVFORK* = cint(0)
 
+# <sys/wait.h>
+proc WEXITSTATUS*(s: cint): cint {.importc, header: "<sys/wait.h>".}
+  ## Exit code, iff WIFEXITED(s)
+proc WTERMSIG*(s: cint): cint {.importc, header: "<sys/wait.h>".}
+  ## Termination signal, iff WIFSIGNALED(s)
+proc WSTOPSIG*(s: cint): cint {.importc, header: "<sys/wait.h>".}
+  ## Stop signal, iff WIFSTOPPED(s)
+proc WIFEXITED*(s: cint): bool {.importc, header: "<sys/wait.h>".}
+  ## True if child exited normally.
+proc WIFSIGNALED*(s: cint): bool {.importc, header: "<sys/wait.h>".}
+  ## True if child exited due to uncaught signal.
+proc WIFSTOPPED*(s: cint): bool {.importc, header: "<sys/wait.h>".}
+  ## True if child is currently stopped.
+proc WIFCONTINUED*(s: cint): bool {.importc, header: "<sys/wait.h>".}
+  ## True if child has been continued.
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 1696c4ed9..6a877be30 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -9,7 +9,7 @@
 
 include "system/inclrtl"
 
-import os, oids, tables, strutils, times, heapqueue
+import os, oids, tables, strutils, times, heapqueue, options
 
 import nativesockets, net, deques
 
@@ -385,68 +385,6 @@ when defined(windows) or defined(nimdoc):
                   dwRemoteAddressLength, LocalSockaddr, LocalSockaddrLength,
                   RemoteSockaddr, RemoteSockaddrLength)
 
-  proc connect*(socket: AsyncFD, address: string, port: Port,
-    domain = nativesockets.AF_INET): Future[void] =
-    ## Connects ``socket`` to server at ``address:port``.
-    ##
-    ## Returns a ``Future`` which will complete when the connection succeeds
-    ## or an error occurs.
-    verifyPresence(socket)
-    var retFuture = newFuture[void]("connect")
-    # Apparently ``ConnectEx`` expects the socket to be initially bound:
-    var saddr: Sockaddr_in
-    saddr.sin_family = int16(toInt(domain))
-    saddr.sin_port = 0
-    saddr.sin_addr.s_addr = INADDR_ANY
-    if bindAddr(socket.SocketHandle, cast[ptr SockAddr](addr(saddr)),
-                  sizeof(saddr).SockLen) < 0'i32:
-      raiseOSError(osLastError())
-
-    var aiList = getAddrInfo(address, port, domain)
-    var success = false
-    var lastError: OSErrorCode
-    var it = aiList
-    while it != nil:
-      # "the OVERLAPPED structure must remain valid until the I/O completes"
-      # http://blogs.msdn.com/b/oldnewthing/archive/2011/02/02/10123392.aspx
-      var ol = PCustomOverlapped()
-      GC_ref(ol)
-      ol.data = CompletionData(fd: socket, cb:
-        proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
-          if not retFuture.finished:
-            if errcode == OSErrorCode(-1):
-              retFuture.complete()
-            else:
-              retFuture.fail(newException(OSError, osErrorMsg(errcode)))
-      )
-
-      var ret = connectEx(socket.SocketHandle, it.ai_addr,
-                          sizeof(Sockaddr_in).cint, nil, 0, nil,
-                          cast[POVERLAPPED](ol))
-      if ret:
-        # Request to connect completed immediately.
-        success = true
-        retFuture.complete()
-        # We don't deallocate ``ol`` here because even though this completed
-        # immediately poll will still be notified about its completion and it will
-        # free ``ol``.
-        break
-      else:
-        lastError = osLastError()
-        if lastError.int32 == ERROR_IO_PENDING:
-          # In this case ``ol`` will be deallocated in ``poll``.
-          success = true
-          break
-        else:
-          GC_unref(ol)
-          success = false
-      it = it.ai_next
-
-    freeAddrInfo(aiList)
-    if not success:
-      retFuture.fail(newException(OSError, osErrorMsg(lastError)))
-    return retFuture
-
   proc recv*(socket: AsyncFD, size: int,
              flags = {SocketFlag.SafeDisconn}): Future[string] =
     ## Reads **up to** ``size`` bytes from ``socket``. Returned future will
@@ -754,8 +692,8 @@ when defined(windows) or defined(nimdoc):
     var lpOutputBuf = newString(lpOutputLen)
     var dwBytesReceived: Dword
     let dwReceiveDataLength = 0.Dword # We don't want any data to be read.
-    let dwLocalAddressLength = Dword(sizeof(Sockaddr_in) + 16)
-    let dwRemoteAddressLength = Dword(sizeof(Sockaddr_in) + 16)
+    let dwLocalAddressLength = Dword(sizeof(Sockaddr_in6) + 16)
+    let dwRemoteAddressLength = Dword(sizeof(Sockaddr_in6) + 16)
 
     template failAccept(errcode) =
       if flags.isDisconnectionError(errcode):
@@ -785,12 +723,14 @@ when defined(windows) or defined(nimdoc):
                              dwLocalAddressLength, dwRemoteAddressLength,
                              addr localSockaddr, addr localLen,
                              addr remoteSockaddr, addr remoteLen)
-        register(clientSock.AsyncFD)
-        # TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186
-        retFuture.complete(
-          (address: $inet_ntoa(cast[ptr Sockaddr_in](remoteSockAddr).sin_addr),
-          client: clientSock.AsyncFD)
-        )
+        try:
+          let address = getAddrString(remoteSockAddr)
+          register(clientSock.AsyncFD)
+          retFuture.complete((address: address, client: clientSock.AsyncFD))
+        except:
+          # getAddrString may raise
+          clientSock.close()
+          retFuture.fail(getCurrentException())
 
     var ol = PCustomOverlapped()
     GC_ref(ol)
@@ -823,20 +763,6 @@ when defined(windows) or defined(nimdoc):
 
     return retFuture
 
-  proc newAsyncNativeSocket*(domain, sockType, protocol: cint): AsyncFD =
-    ## Creates a new socket and registers it with the dispatcher implicitly.
-    result = newNativeSocket(domain, sockType, protocol).AsyncFD
-    result.SocketHandle.setBlocking(false)
-    register(result)
-
-  proc newAsyncNativeSocket*(domain: Domain = nativesockets.AF_INET,
-                             sockType: SockType = SOCK_STREAM,
-                             protocol: Protocol = IPPROTO_TCP): AsyncFD =
-    ## Creates a new socket and registers it with the dispatcher implicitly.
-    result = newNativeSocket(domain, sockType, protocol).AsyncFD
-    result.SocketHandle.setBlocking(false)
-    register(result)
-
   proc closeSocket*(socket: AsyncFD) =
     ## Closes a socket and ensures that it is unregistered.
     socket.SocketHandle.close()
@@ -1015,23 +941,6 @@ else:
     var data = PData(fd: fd, readCBs: @[], writeCBs: @[])
     p.selector.register(fd.SocketHandle, {}, data.RootRef)
 
-  proc newAsyncNativeSocket*(domain: cint, sockType: cint,
-                             protocol: cint): AsyncFD =
-    result = newNativeSocket(domain, sockType, protocol).AsyncFD
-    result.SocketHandle.setBlocking(false)
-    when defined(macosx):
-      result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
-    register(result)
-
-  proc newAsyncNativeSocket*(domain: Domain = AF_INET,
-                             sockType: SockType = SOCK_STREAM,
-                             protocol: Protocol = IPPROTO_TCP): AsyncFD =
-    result = newNativeSocket(domain, sockType, protocol).AsyncFD
-    result.SocketHandle.setBlocking(false)
-    when defined(macosx):
-      result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
-    register(result)
-
   proc closeSocket*(sock: AsyncFD) =
     let disp = getGlobalDispatcher()
     disp.selector.unregister(sock.SocketHandle)
@@ -1115,50 +1024,6 @@ else:
     # Callback queue processing
     processPendingCallbacks(p)
 
-  proc connect*(socket: AsyncFD, address: string, port: Port,
-    domain = AF_INET): Future[void] =
-    var retFuture = newFuture[void]("connect")
-
-    proc cb(fd: AsyncFD): bool =
-      var ret = SocketHandle(fd).getSockOptInt(cint(SOL_SOCKET), cint(SO_ERROR))
-      if ret == 0:
-          # We have connected.
-          retFuture.complete()
-          return true
-      elif ret == EINTR:
-          # interrupted, keep waiting
-          return false
-      else:
-          retFuture.fail(newException(OSError, osErrorMsg(OSErrorCode(ret))))
-          return true
-
-    assert getSockDomain(socket.SocketHandle) == domain
-    var aiList = getAddrInfo(address, port, domain)
-    var success = false
-    var lastError: OSErrorCode
-    var it = aiList
-    while it != nil:
-      var ret = connect(socket.SocketHandle, it.ai_addr, it.ai_addrlen.Socklen)
-      if ret == 0:
-        # Request to connect completed immediately.
-        success = true
-        retFuture.complete()
-        break
-      else:
-        lastError = osLastError()
-        if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
-          success = true
-          addWrite(socket, cb)
-          break
-        else:
-          success = false
-      it = it.ai_next
-
-    freeAddrInfo(aiList)
-    if not success:
-      retFuture.fail(newException(OSError, osErrorMsg(lastError)))
-    return retFuture
-
   proc recv*(socket: AsyncFD, size: int,
              flags = {SocketFlag.SafeDisconn}): Future[string] =
     var retFuture = newFuture[string]("recv")
@@ -1320,11 +1185,20 @@ else:
           else:
             retFuture.fail(newException(OSError, osErrorMsg(lastError)))
       else:
-        register(client.AsyncFD)
-        retFuture.complete((getAddrString(cast[ptr SockAddr](addr sockAddress)), client.AsyncFD))
+        try:
+          let address = getAddrString(cast[ptr SockAddr](addr sockAddress))
+          register(client.AsyncFD)
+          retFuture.complete((address, client.AsyncFD))
+        except:
+          # getAddrString may raise
+          client.close()
+          retFuture.fail(getCurrentException())
     addRead(socket, cb)
     return retFuture
 
+# Common procedures between current and upcoming asyncdispatch
+include includes.asynccommon
+
 proc sleepAsync*(ms: int): Future[void] =
   ## Suspends the execution of the current async procedure for the next
   ## ``ms`` milliseconds.
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index 1ec751a64..11b7998b2 100644
--- a/lib/pure/asyncnet.nim
+++ b/lib/pure/asyncnet.nim
@@ -244,6 +244,17 @@ when defineSsl:
           else:
             raiseSSLError("Socket has been disconnected")
 
+proc dial*(address: string, port: Port, protocol = IPPROTO_TCP,
+           buffered = true): Future[AsyncSocket] {.async.} =
+  ## Establishes connection to the specified ``address``:``port`` pair via the
+  ## specified protocol. The procedure iterates through possible
+  ## resolutions of the ``address`` until it succeeds, meaning that it
+  ## seamlessly works with both IPv4 and IPv6.
+  ## Returns AsyncSocket ready to send or receive data.
+  let asyncFd = await asyncdispatch.dial(address, port, protocol)
+  let sockType = protocol.toSockType()
+  let domain = getSockDomain(asyncFd.SocketHandle)
+  result = newAsyncSocket(asyncFd, domain, sockType, protocol, buffered)
 
 proc connect*(socket: AsyncSocket, address: string, port: Port) {.async.} =
   ## Connects ``socket`` to server at ``address:port``.
diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim
index eee03d7ae..4b0d08292 100644
--- a/lib/pure/base64.nim
+++ b/lib/pure/base64.nim
@@ -44,21 +44,23 @@
 const
   cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
 
-template encodeInternal(s: expr, lineLen: int, newLine: string): stmt {.immediate.} =
+template encodeInternal(s: typed, lineLen: int, newLine: string): untyped =
   ## encodes `s` into base64 representation. After `lineLen` characters, a
   ## `newline` is added.
   var total = ((len(s) + 2) div 3) * 4
-  var numLines = (total + lineLen - 1) div lineLen
+  let numLines = (total + lineLen - 1) div lineLen
   if numLines > 0: inc(total, (numLines - 1) * newLine.len)
 
   result = newString(total)
-  var i = 0
-  var r = 0
-  var currLine = 0
+  var 
+    i = 0
+    r = 0
+    currLine = 0
   while i < s.len - 2:
-    var a = ord(s[i])
-    var b = ord(s[i+1])
-    var c = ord(s[i+2])
+    let
+      a = ord(s[i])
+      b = ord(s[i+1])
+      c = ord(s[i+2])
     result[r] = cb64[a shr 2]
     result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
     result[r+2] = cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)]
@@ -74,8 +76,9 @@ template encodeInternal(s: expr, lineLen: int, newLine: string): stmt {.immediat
       currLine = 0
 
   if i < s.len-1:
-    var a = ord(s[i])
-    var b = ord(s[i+1])
+    let 
+      a = ord(s[i])
+      b = ord(s[i+1])
     result[r] = cb64[a shr 2]
     result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
     result[r+2] = cb64[((b and 0x0F) shl 2)]
@@ -83,7 +86,7 @@ template encodeInternal(s: expr, lineLen: int, newLine: string): stmt {.immediat
     if r+4 != result.len:
       setLen(result, r+4)
   elif i < s.len:
-    var a = ord(s[i])
+    let a = ord(s[i])
     result[r] = cb64[a shr 2]
     result[r+1] = cb64[(a and 3) shl 4]
     result[r+2] = '='
@@ -127,15 +130,17 @@ proc decode*(s: string): string =
   # total is an upper bound, as we will skip arbitrary whitespace:
   result = newString(total)
 
-  var i = 0
-  var r = 0
+  var 
+    i = 0
+    r = 0
   while true:
     while s[i] in Whitespace: inc(i)
     if i < s.len-3:
-      var a = s[i].decodeByte
-      var b = s[i+1].decodeByte
-      var c = s[i+2].decodeByte
-      var d = s[i+3].decodeByte
+      let
+        a = s[i].decodeByte
+        b = s[i+1].decodeByte
+        c = s[i+2].decodeByte
+        d = s[i+3].decodeByte
 
       result[r] = chr((a shl 2) and 0xff or ((b shr 4) and 0x03))
       result[r+1] = chr((b shl 4) and 0xff or ((c shr 2) and 0x0F))
@@ -169,4 +174,4 @@ when isMainModule:
   for t in items(tests):
     assert decode(encode(t)) == t
     assert decode(encode(t, lineLen=40)) == t
-    assert decode(encode(t, lineLen=76)) == t
\ No newline at end of file
+    assert decode(encode(t, lineLen=76)) == t
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index b6c00966f..969802cfc 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -785,7 +785,7 @@ proc sort*[A, B](t: OrderedTableRef[A, B],
   t[].sort(cmp)
 
 proc del*[A, B](t: var OrderedTable[A, B], key: A) =
-  ## deletes `key` from ordered hash table `t`. O(n) comlexity.
+  ## deletes `key` from ordered hash table `t`. O(n) complexity.
   var n: OrderedKeyValuePairSeq[A, B]
   newSeq(n, len(t.data))
   var h = t.first
@@ -804,7 +804,7 @@ proc del*[A, B](t: var OrderedTable[A, B], key: A) =
     h = nxt
 
 proc del*[A, B](t: var OrderedTableRef[A, B], key: A) =
-  ## deletes `key` from ordered hash table `t`. O(n) comlexity.
+  ## deletes `key` from ordered hash table `t`. O(n) complexity.
   t[].del(key)
 
 # ------------------------------ count tables -------------------------------
diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim
index 8090cd49d..7d850798c 100644
--- a/lib/pure/cookies.nim
+++ b/lib/pure/cookies.nim
@@ -39,7 +39,7 @@ proc setCookie*(key, value: string, domain = "", path = "",
   if domain != "": result.add("; Domain=" & domain)
   if path != "": result.add("; Path=" & path)
   if expires != "": result.add("; Expires=" & expires)
-  if secure: result.add("; secure")
+  if secure: result.add("; Secure")
   if httpOnly: result.add("; HttpOnly")
 
 proc setCookie*(key, value: string, expires: TimeInfo,
@@ -50,7 +50,7 @@ proc setCookie*(key, value: string, expires: TimeInfo,
   ##
   ## **Note:** UTC is assumed as the timezone for ``expires``.
   return setCookie(key, value, domain, path,
-                   format(expires, "ddd',' dd MMM yyyy HH:mm:ss 'UTC'"),
+                   format(expires, "ddd',' dd MMM yyyy HH:mm:ss 'GMT'"),
                    noname, secure, httpOnly)
 
 when isMainModule:
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 62c7e2067..1b8a20b65 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -434,7 +434,7 @@ proc `[]=`*(p: var MultipartData, name: string,
   ##     "<html><head></head><body><p>test</p></body></html>")
   p.add(name, file.content, file.name, file.contentType)
 
-proc format(p: MultipartData): tuple[header, body: string] =
+proc format(p: MultipartData): tuple[contentType, body: string] =
   if p == nil or p.content == nil or p.content.len == 0:
     return ("", "")
 
@@ -449,7 +449,7 @@ proc format(p: MultipartData): tuple[header, body: string] =
     if not found:
       break
 
-  result.header = "Content-Type: multipart/form-data; boundary=" & bound & "\c\L"
+  result.contentType = "multipart/form-data; boundary=" & bound
   result.body = ""
   for s in p.content:
     result.body.add("--" & bound & "\c\L" & s)
@@ -640,7 +640,7 @@ proc post*(url: string, extraHeaders = "", body = "",
   ## ``multipart/form-data`` POSTs comfortably.
   ##
   ## **Deprecated since version 0.15.0**: use ``HttpClient.post`` instead.
-  let (mpHeaders, mpBody) = format(multipart)
+  let (mpContentType, mpBody) = format(multipart)
 
   template withNewLine(x): untyped =
     if x.len > 0 and not x.endsWith("\c\L"):
@@ -650,9 +650,12 @@ proc post*(url: string, extraHeaders = "", body = "",
 
   var xb = mpBody.withNewLine() & body
 
-  var xh = extraHeaders.withNewLine() & mpHeaders.withNewLine() &
+  var xh = extraHeaders.withNewLine() &
     withNewLine("Content-Length: " & $len(xb))
 
+  if not multipart.isNil:
+    xh.add(withNewLine("Content-Type: " & mpContentType))
+
   result = request(url, httpPOST, xh, xb, sslContext, timeout, userAgent,
                    proxy)
   var lastURL = url
@@ -1030,32 +1033,38 @@ proc newConnection(client: HttpClient | AsyncHttpClient,
   if client.currentURL.hostname != url.hostname or
       client.currentURL.scheme != url.scheme or
       client.currentURL.port != url.port:
+    let isSsl = url.scheme.toLowerAscii() == "https"
+
+    if isSsl and not defined(ssl):
+      raise newException(HttpRequestError,
+        "SSL support is not available. Cannot connect over SSL.")
+
     if client.connected:
       client.close()
 
-    when client is HttpClient:
-      client.socket = newSocket()
-    elif client is AsyncHttpClient:
-      client.socket = newAsyncSocket()
-    else: {.fatal: "Unsupported client type".}
-
     # TODO: I should be able to write 'net.Port' here...
     let port =
       if url.port == "":
-        if url.scheme.toLower() == "https":
+        if isSsl:
           nativesockets.Port(443)
         else:
           nativesockets.Port(80)
       else: nativesockets.Port(url.port.parseInt)
 
-    if url.scheme.toLower() == "https":
-      when defined(ssl):
-        client.sslContext.wrapSocket(client.socket)
-      else:
-        raise newException(HttpRequestError,
-                  "SSL support is not available. Cannot connect over SSL.")
+    when client is HttpClient:
+      client.socket = await net.dial(url.hostname, port)
+    elif client is AsyncHttpClient:
+      client.socket = await asyncnet.dial(url.hostname, port)
+    else: {.fatal: "Unsupported client type".}
+
+    when defined(ssl):
+      if isSsl:
+        try:
+          client.sslContext.wrapConnectedSocket(client.socket, handshakeAsClient)
+        except:
+          client.socket.close()
+          raise getCurrentException()
 
-    await client.socket.connect(url.hostname, port)
     client.currentURL = url
     client.connected = true
 
@@ -1188,7 +1197,7 @@ proc post*(client: HttpClient | AsyncHttpClient, url: string, body = "",
   ##
   ## This procedure will follow redirects up to a maximum number of redirects
   ## specified in ``client.maxRedirects``.
-  let (mpHeader, mpBody) = format(multipart)
+  let (mpContentType, mpBody) = format(multipart)
   # TODO: Support FutureStream for `body` parameter.
   template withNewLine(x): untyped =
     if x.len > 0 and not x.endsWith("\c\L"):
@@ -1199,7 +1208,7 @@ proc post*(client: HttpClient | AsyncHttpClient, url: string, body = "",
 
   var headers = newHttpHeaders()
   if multipart != nil:
-    headers["Content-Type"] = mpHeader.split(": ")[1]
+    headers["Content-Type"] = mpContentType
   headers["Content-Length"] = $len(xb)
 
   result = await client.requestAux(url, $HttpPOST, xb, headers)
diff --git a/lib/pure/includes/asynccommon.nim b/lib/pure/includes/asynccommon.nim
new file mode 100644
index 000000000..a7d2f803f
--- /dev/null
+++ b/lib/pure/includes/asynccommon.nim
@@ -0,0 +1,201 @@
+template newAsyncNativeSocketImpl(domain, sockType, protocol) =
+  let handle = newNativeSocket(domain, sockType, protocol)
+  if handle == osInvalidSocket:
+    raiseOSError(osLastError())
+  handle.setBlocking(false)
+  when defined(macosx):
+    handle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
+  result = handle.AsyncFD
+  register(result)
+
+proc newAsyncNativeSocket*(domain: cint, sockType: cint,
+                           protocol: cint): AsyncFD =
+  newAsyncNativeSocketImpl(domain, sockType, protocol)
+
+proc newAsyncNativeSocket*(domain: Domain = Domain.AF_INET,
+                           sockType: SockType = SOCK_STREAM,
+                           protocol: Protocol = IPPROTO_TCP): AsyncFD =
+  newAsyncNativeSocketImpl(domain, sockType, protocol)
+
+when defined(windows) or defined(nimdoc):
+  proc bindToDomain(handle: SocketHandle, domain: Domain) =
+    # Extracted into a separate proc, because connect() on Windows requires
+    # the socket to be initially bound.
+    template doBind(saddr) =
+      if bindAddr(handle, cast[ptr SockAddr](addr(saddr)),
+                  sizeof(saddr).SockLen) < 0'i32:
+        raiseOSError(osLastError())
+
+    if domain == Domain.AF_INET6:
+      var saddr: Sockaddr_in6
+      saddr.sin6_family = int16(toInt(domain))
+      doBind(saddr)
+    else:
+      var saddr: Sockaddr_in
+      saddr.sin_family = int16(toInt(domain))
+      doBind(saddr)
+
+  proc doConnect(socket: AsyncFD, addrInfo: ptr AddrInfo): Future[void] =
+    let retFuture = newFuture[void]("doConnect")
+    result = retFuture
+
+    var ol = PCustomOverlapped()
+    GC_ref(ol)
+    ol.data = CompletionData(fd: socket, cb:
+      proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
+        if not retFuture.finished:
+          if errcode == OSErrorCode(-1):
+            retFuture.complete()
+          else:
+            retFuture.fail(newException(OSError, osErrorMsg(errcode)))
+    )
+
+    let ret = connectEx(socket.SocketHandle, addrInfo.ai_addr,
+                        cint(addrInfo.ai_addrlen), nil, 0, nil,
+                        cast[POVERLAPPED](ol))
+    if ret:
+      # Request to connect completed immediately.
+      retFuture.complete()
+      # We don't deallocate ``ol`` here because even though this completed
+      # immediately poll will still be notified about its completion and it
+      # will free ``ol``.
+    else:
+      let lastError = osLastError()
+      if lastError.int32 != ERROR_IO_PENDING:
+        # With ERROR_IO_PENDING ``ol`` will be deallocated in ``poll``,
+        # and the future will be completed/failed there, too.
+        GC_unref(ol)
+        retFuture.fail(newException(OSError, osErrorMsg(lastError)))
+else:
+  proc doConnect(socket: AsyncFD, addrInfo: ptr AddrInfo): Future[void] =
+    let retFuture = newFuture[void]("doConnect")
+    result = retFuture
+
+    proc cb(fd: AsyncFD): bool =
+      let ret = SocketHandle(fd).getSockOptInt(
+        cint(SOL_SOCKET), cint(SO_ERROR))
+      if ret == 0:
+        # We have connected.
+        retFuture.complete()
+        return true
+      elif ret == EINTR:
+        # interrupted, keep waiting
+        return false
+      else:
+        retFuture.fail(newException(OSError, osErrorMsg(OSErrorCode(ret))))
+        return true
+
+    let ret = connect(socket.SocketHandle,
+                      addrInfo.ai_addr,
+                      addrInfo.ai_addrlen.Socklen)
+    if ret == 0:
+      # Request to connect completed immediately.
+      retFuture.complete()
+    else:
+      let lastError = osLastError()
+      if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
+        addWrite(socket, cb)
+      else:
+        retFuture.fail(newException(OSError, osErrorMsg(lastError)))
+
+template asyncAddrInfoLoop(addrInfo: ptr AddrInfo, fd: untyped,
+                           protocol: Protocol = IPPROTO_RAW) =
+  ## Iterates through the AddrInfo linked list asynchronously
+  ## until the connection can be established.
+  const shouldCreateFd = not declared(fd)
+
+  when shouldCreateFd:
+    let sockType = protocol.toSockType()
+
+    var fdPerDomain: array[low(Domain).ord..high(Domain).ord, AsyncFD]
+    for i in low(fdPerDomain)..high(fdPerDomain):
+      fdPerDomain[i] = osInvalidSocket.AsyncFD
+    template closeUnusedFds(domainToKeep = -1) {.dirty.} =
+      for i, fd in fdPerDomain:
+        if fd != osInvalidSocket.AsyncFD and i != domainToKeep:
+          fd.closeSocket()
+
+  var lastException: ref Exception
+  var curAddrInfo = addrInfo
+  var domain: Domain
+  when shouldCreateFd:
+    var curFd: AsyncFD
+  else:
+    var curFd = fd
+  proc tryNextAddrInfo(fut: Future[void]) {.gcsafe.} =
+    if fut == nil or fut.failed:
+      if fut != nil:
+        lastException = fut.readError()
+
+      while curAddrInfo != nil:
+        let domainOpt = curAddrInfo.ai_family.toKnownDomain()
+        if domainOpt.isSome:
+          domain = domainOpt.unsafeGet()
+          break
+        curAddrInfo = curAddrInfo.ai_next
+
+      if curAddrInfo == nil:
+        freeAddrInfo(addrInfo)
+        when shouldCreateFd:
+          closeUnusedFds()
+        if lastException != nil:
+          retFuture.fail(lastException)
+        else:
+          retFuture.fail(newException(
+            IOError, "Couldn't resolve address: " & address))
+        return
+
+      when shouldCreateFd:
+        curFd = fdPerDomain[ord(domain)]
+        if curFd == osInvalidSocket.AsyncFD:
+          try:
+            curFd = newAsyncNativeSocket(domain, sockType, protocol)
+          except:
+            freeAddrInfo(addrInfo)
+            closeUnusedFds()
+            raise getCurrentException()
+          when defined(windows):
+            curFd.SocketHandle.bindToDomain(domain)
+          fdPerDomain[ord(domain)] = curFd
+
+      doConnect(curFd, curAddrInfo).callback = tryNextAddrInfo
+      curAddrInfo = curAddrInfo.ai_next
+    else:
+      freeAddrInfo(addrInfo)
+      when shouldCreateFd:
+        closeUnusedFds(ord(domain))
+        retFuture.complete(curFd)
+      else:
+        retFuture.complete()
+
+  tryNextAddrInfo(nil)
+
+proc dial*(address: string, port: Port,
+           protocol: Protocol = IPPROTO_TCP): Future[AsyncFD] =
+  ## Establishes connection to the specified ``address``:``port`` pair via the
+  ## specified protocol. The procedure iterates through possible
+  ## resolutions of the ``address`` until it succeeds, meaning that it
+  ## seamlessly works with both IPv4 and IPv6.
+  ## Returns the async file descriptor, registered in the dispatcher of
+  ## the current thread, ready to send or receive data.
+  let retFuture = newFuture[AsyncFD]("dial")
+  result = retFuture
+  let sockType = protocol.toSockType()
+
+  let aiList = getAddrInfo(address, port, Domain.AF_UNSPEC, sockType, protocol)
+  asyncAddrInfoLoop(aiList, noFD, protocol)
+
+proc connect*(socket: AsyncFD, address: string, port: Port,
+              domain = Domain.AF_INET): Future[void] =
+  let retFuture = newFuture[void]("connect")
+  result = retFuture
+
+  when defined(windows):
+    verifyPresence(socket)
+  else:
+    assert getSockDomain(socket.SocketHandle) == domain
+
+  let aiList = getAddrInfo(address, port, domain)
+  when defined(windows):
+    socket.SocketHandle.bindToDomain(domain)
+  asyncAddrInfoLoop(aiList, socket)
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index b3fc47749..564f952d3 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -1213,22 +1213,22 @@ when not defined(js):
   proc parseJson*(s: Stream, filename: string): JsonNode =
     ## Parses from a stream `s` into a `JsonNode`. `filename` is only needed
     ## for nice error messages.
-    ## If `s` contains extra data, it will raising `JsonParsingError`.
+    ## If `s` contains extra data, it will raise `JsonParsingError`.
     var p: JsonParser
     p.open(s, filename)
     defer: p.close()
     discard getTok(p) # read first token
     result = p.parseJson()
-    eat(p, tkEof) # check there are no exstra data
+    eat(p, tkEof) # check if there is no extra data
 
   proc parseJson*(buffer: string): JsonNode =
     ## Parses JSON from `buffer`.
-    ## If `buffer` contains extra data, it will raising `JsonParsingError`.
+    ## If `buffer` contains extra data, it will raise `JsonParsingError`.
     result = parseJson(newStringStream(buffer), "input")
 
   proc parseFile*(filename: string): JsonNode =
     ## Parses `file` into a `JsonNode`.
-    ## If `file` contains extra data, it will raising `JsonParsingError`.
+    ## If `file` contains extra data, it will raise `JsonParsingError`.
     var stream = newFileStream(filename, fmRead)
     if stream == nil:
       raise newException(IOError, "cannot read from file: " & filename)
@@ -1502,7 +1502,7 @@ proc processObjField(field, jsonNode: NimNode): seq[NimNode] =
   doAssert result.len > 0
 
 proc processType(typeName: NimNode, obj: NimNode,
-                 jsonNode: NimNode): NimNode {.compileTime.} =
+                 jsonNode: NimNode, isRef: bool): NimNode {.compileTime.} =
   ## Process a type such as ``Sym "float"`` or ``ObjectTy ...``.
   ##
   ## Sample ``ObjectTy``:
@@ -1524,6 +1524,20 @@ proc processType(typeName: NimNode, obj: NimNode,
     for field in obj[2]:
       let nodes = processObjField(field, jsonNode)
       result.add(nodes)
+
+    # Object might be null. So we need to check for that.
+    if isRef:
+      result = quote do:
+        verifyJsonKind(`jsonNode`, {JObject, JNull}, astToStr(`jsonNode`))
+        if `jsonNode`.kind == JNull:
+          nil
+        else:
+          `result`
+    else:
+      result = quote do:
+        verifyJsonKind(`jsonNode`, {JObject}, astToStr(`jsonNode`));
+        `result`
+
   of nnkEnumTy:
     let instType = toIdentNode(getTypeInst(typeName))
     let getEnumCall = createGetEnumCall(jsonNode, instType)
@@ -1536,8 +1550,8 @@ proc processType(typeName: NimNode, obj: NimNode,
     of "float":
       result = quote do:
         (
-          verifyJsonKind(`jsonNode`, {JFloat}, astToStr(`jsonNode`));
-          `jsonNode`.fnum
+          verifyJsonKind(`jsonNode`, {JFloat, JInt}, astToStr(`jsonNode`));
+          if `jsonNode`.kind == JFloat: `jsonNode`.fnum else: `jsonNode`.num.float
         )
     of "string":
       result = quote do:
@@ -1551,6 +1565,12 @@ proc processType(typeName: NimNode, obj: NimNode,
           verifyJsonKind(`jsonNode`, {JInt}, astToStr(`jsonNode`));
           `jsonNode`.num.int
         )
+    of "biggestint":
+      result = quote do:
+        (
+          verifyJsonKind(`jsonNode`, {JInt}, astToStr(`jsonNode`));
+          `jsonNode`.num
+        )
     of "bool":
       result = quote do:
         (
@@ -1585,7 +1605,7 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
         typeName = typeName[0 .. ^12]
 
       let obj = getType(typeSym[1])
-      result = processType(newIdentNode(typeName), obj, jsonNode)
+      result = processType(newIdentNode(typeName), obj, jsonNode, true)
     of "seq":
       let seqT = typeSym[1]
       let forLoopI = newIdentNode("i")
@@ -1605,17 +1625,21 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
     else:
       # Generic type.
       let obj = getType(typeSym)
-      result = processType(typeSym, obj, jsonNode)
+      result = processType(typeSym, obj, jsonNode, false)
   of nnkSym:
     let obj = getType(typeSym)
-    result = processType(typeSym, obj, jsonNode)
+    if obj.kind == nnkBracketExpr:
+      # When `Sym "Foo"` turns out to be a `ref object`.
+      result = createConstructor(obj, jsonNode)
+    else:
+      result = processType(typeSym, obj, jsonNode, false)
   else:
     doAssert false, "Unable to create constructor for: " & $typeSym.kind
 
   doAssert(not result.isNil(), "Constructor not initialised.")
 
 proc postProcess(node: NimNode): NimNode
-proc postProcessValue(value: NimNode, depth=0): NimNode =
+proc postProcessValue(value: NimNode): NimNode =
   ## Looks for object constructors and calls the ``postProcess`` procedure
   ## on them. Otherwise it just returns the node as-is.
   case value.kind
@@ -1736,9 +1760,10 @@ macro to*(node: JsonNode, T: typedesc): untyped =
   doAssert(($typeNode[0]).normalize == "typedesc")
 
   result = createConstructor(typeNode[1], node)
-  result = postProcess(result)
+  # TODO: Rename postProcessValue and move it (?)
+  result = postProcessValue(result)
 
-  #echo(toStrLit(result))
+  # echo(toStrLit(result))
 
 when false:
   import os
diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim
index fa3fa4aea..7568408a6 100644
--- a/lib/pure/nativesockets.nim
+++ b/lib/pure/nativesockets.nim
@@ -12,7 +12,7 @@
 
 # TODO: Clean up the exports a bit and everything else in general.
 
-import os
+import os, options
 
 when hostOS == "solaris":
   {.passl: "-lsocket -lnsl".}
@@ -52,9 +52,11 @@ type
   Domain* = enum    ## domain, which specifies the protocol family of the
                     ## created socket. Other domains than those that are listed
                     ## here are unsupported.
-    AF_UNIX,        ## for local socket (using a file). Unsupported on Windows.
+    AF_UNSPEC = 0,  ## unspecified domain (can be detected automatically by
+                    ## some procedures, such as getaddrinfo)
+    AF_UNIX = 1,    ## for local socket (using a file). Unsupported on Windows.
     AF_INET = 2,    ## for network protocol IPv4 or
-    AF_INET6 = 23   ## for network protocol IPv6.
+    AF_INET6 = when defined(macosx): 30 else: 23   ## for network protocol IPv6.
 
   SockType* = enum     ## second argument to `socket` proc
     SOCK_STREAM = 1,   ## reliable stream-oriented service or Stream Sockets
@@ -125,10 +127,19 @@ proc toInt*(p: Protocol): cint
 when not useWinVersion:
   proc toInt(domain: Domain): cshort =
     case domain
+    of AF_UNSPEC:      result = posix.AF_UNSPEC.cshort
     of AF_UNIX:        result = posix.AF_UNIX.cshort
     of AF_INET:        result = posix.AF_INET.cshort
     of AF_INET6:       result = posix.AF_INET6.cshort
-    else: discard
+
+  proc toKnownDomain*(family: cint): Option[Domain] =
+    ## Converts the platform-dependent ``cint`` to the Domain or none(),
+    ## if the ``cint`` is not known.
+    result = if   family == posix.AF_UNSPEC: some(Domain.AF_UNSPEC)
+             elif family == posix.AF_UNIX:   some(Domain.AF_UNIX)
+             elif family == posix.AF_INET:   some(Domain.AF_INET)
+             elif family == posix.AF_INET6:  some(Domain.AF_INET6)
+             else: none(Domain)
 
   proc toInt(typ: SockType): cint =
     case typ
@@ -136,7 +147,6 @@ when not useWinVersion:
     of SOCK_DGRAM:     result = posix.SOCK_DGRAM
     of SOCK_SEQPACKET: result = posix.SOCK_SEQPACKET
     of SOCK_RAW:       result = posix.SOCK_RAW
-    else: discard
 
   proc toInt(p: Protocol): cint =
     case p
@@ -146,18 +156,33 @@ when not useWinVersion:
     of IPPROTO_IPV6:   result = posix.IPPROTO_IPV6
     of IPPROTO_RAW:    result = posix.IPPROTO_RAW
     of IPPROTO_ICMP:   result = posix.IPPROTO_ICMP
-    else: discard
 
 else:
   proc toInt(domain: Domain): cshort =
     result = toU16(ord(domain))
 
+  proc toKnownDomain*(family: cint): Option[Domain] =
+    ## Converts the platform-dependent ``cint`` to the Domain or none(),
+    ## if the ``cint`` is not known.
+    result = if   family == winlean.AF_UNSPEC: some(Domain.AF_UNSPEC)
+             elif family == winlean.AF_INET:   some(Domain.AF_INET)
+             elif family == winlean.AF_INET6:  some(Domain.AF_INET6)
+             else: none(Domain)
+
   proc toInt(typ: SockType): cint =
     result = cint(ord(typ))
 
   proc toInt(p: Protocol): cint =
     result = cint(ord(p))
 
+proc toSockType*(protocol: Protocol): SockType =
+  result = case protocol
+  of IPPROTO_TCP:
+    SOCK_STREAM
+  of IPPROTO_UDP:
+    SOCK_DGRAM
+  of IPPROTO_IP, IPPROTO_IPV6, IPPROTO_RAW, IPPROTO_ICMP:
+    SOCK_RAW
 
 proc newNativeSocket*(domain: Domain = AF_INET,
                       sockType: SockType = SOCK_STREAM,
@@ -392,14 +417,14 @@ proc getHostname*(): string {.tags: [ReadIOEffect].} =
 
 proc getSockDomain*(socket: SocketHandle): Domain =
   ## returns the socket's domain (AF_INET or AF_INET6).
-  var name: SockAddr
+  var name: Sockaddr_in6
   var namelen = sizeof(name).SockLen
   if getsockname(socket, cast[ptr SockAddr](addr(name)),
                  addr(namelen)) == -1'i32:
     raiseOSError(osLastError())
-  if name.sa_family == nativeAfInet:
+  if name.sin6_family == nativeAfInet:
     result = AF_INET
-  elif name.sa_family == nativeAfInet6:
+  elif name.sin6_family == nativeAfInet6:
     result = AF_INET6
   else:
     raiseOSError(osLastError(), "unknown socket family in getSockFamily")
@@ -410,17 +435,23 @@ proc getAddrString*(sockAddr: ptr SockAddr): string =
   if sockAddr.sa_family == nativeAfInet:
     result = $inet_ntoa(cast[ptr Sockaddr_in](sockAddr).sin_addr)
   elif sockAddr.sa_family == nativeAfInet6:
+    let addrLen = when not useWinVersion: posix.INET6_ADDRSTRLEN
+                  else: 46 # it's actually 46 in both cases
+    result = newString(addrLen)
+    let addr6 = addr cast[ptr Sockaddr_in6](sockAddr).sin6_addr
     when not useWinVersion:
-      # TODO: Windows
-      result = newString(posix.INET6_ADDRSTRLEN)
-      let addr6 = addr cast[ptr Sockaddr_in6](sockAddr).sin6_addr
-      discard posix.inet_ntop(posix.AF_INET6, addr6, result.cstring,
-          result.len.int32)
+      if posix.inet_ntop(posix.AF_INET6, addr6, addr result[0],
+                         result.len.int32) == nil:
+        raiseOSError(osLastError())
       if posix.IN6_IS_ADDR_V4MAPPED(addr6) != 0:
         result = result.substr("::ffff:".len)
+    else:
+      if winlean.inet_ntop(winlean.AF_INET6, addr6, addr result[0],
+                           result.len.int32) == nil:
+        raiseOSError(osLastError())
+    setLen(result, len(cstring(result)))
   else:
-    raiseOSError(osLastError(), "unknown socket family in getAddrString")
-
+    raise newException(IOError, "Unknown socket family in getAddrString")
 
 proc getSockName*(socket: SocketHandle): Port =
   ## returns the socket's associated port number.
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index 56f8b9399..d175bd537 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -66,7 +66,7 @@
 ##
 
 {.deadCodeElim: on.}
-import nativesockets, os, strutils, parseutils, times, sets
+import nativesockets, os, strutils, parseutils, times, sets, options
 export Port, `$`, `==`
 export Domain, SockType, Protocol
 
@@ -669,7 +669,7 @@ proc close*(socket: Socket) =
   ## Closes a socket.
   try:
     when defineSsl:
-      if socket.isSSL:
+      if socket.isSSL and socket.sslHandle != nil:
         ErrClearError()
         # As we are closing the underlying socket immediately afterwards,
         # it is valid, under the TLS standard, to perform a unidirectional
@@ -1477,6 +1477,63 @@ proc isIpAddress*(address_str: string): bool {.tags: [].} =
     return false
   return true
 
+proc dial*(address: string, port: Port,
+           protocol = IPPROTO_TCP, buffered = true): Socket
+           {.tags: [ReadIOEffect, WriteIOEffect].} =
+  ## Establishes connection to the specified ``address``:``port`` pair via the
+  ## specified protocol. The procedure iterates through possible
+  ## resolutions of the ``address`` until it succeeds, meaning that it
+  ## seamlessly works with both IPv4 and IPv6.
+  ## Returns Socket ready to send or receive data.
+  let sockType = protocol.toSockType()
+
+  let aiList = getAddrInfo(address, port, AF_UNSPEC, sockType, protocol)
+
+  var fdPerDomain: array[low(Domain).ord..high(Domain).ord, SocketHandle]
+  for i in low(fdPerDomain)..high(fdPerDomain):
+    fdPerDomain[i] = osInvalidSocket
+  template closeUnusedFds(domainToKeep = -1) {.dirty.} =
+    for i, fd in fdPerDomain:
+      if fd != osInvalidSocket and i != domainToKeep:
+        fd.close()
+
+  var success = false
+  var lastError: OSErrorCode
+  var it = aiList
+  var domain: Domain
+  var lastFd: SocketHandle
+  while it != nil:
+    let domainOpt = it.ai_family.toKnownDomain()
+    if domainOpt.isNone:
+      it = it.ai_next
+      continue
+    domain = domainOpt.unsafeGet()
+    lastFd = fdPerDomain[ord(domain)]
+    if lastFd == osInvalidSocket:
+      lastFd = newNativeSocket(domain, sockType, protocol)
+      if lastFd == osInvalidSocket:
+        # we always raise if socket creation failed, because it means a
+        # network system problem (e.g. not enough FDs), and not an unreachable
+        # address.
+        let err = osLastError()
+        freeAddrInfo(aiList)
+        closeUnusedFds()
+        raiseOSError(err)
+      fdPerDomain[ord(domain)] = lastFd
+    if connect(lastFd, it.ai_addr, it.ai_addrlen.SockLen) == 0'i32:
+      success = true
+      break
+    lastError = osLastError()
+    it = it.ai_next
+  freeAddrInfo(aiList)
+  closeUnusedFds(ord(domain))
+
+  if success:
+    result = newSocket(lastFd, domain, sockType, protocol)
+  elif lastError != 0.OSErrorCode:
+    raiseOSError(lastError)
+  else:
+    raise newException(IOError, "Couldn't resolve address: " & address)
 
 proc connect*(socket: Socket, address: string,
     port = Port(0)) {.tags: [ReadIOEffect].} =
diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim
index e4c97b260..60b53dbe0 100644
--- a/lib/pure/oids.nim
+++ b/lib/pure/oids.nim
@@ -69,10 +69,9 @@ var
 proc genOid*(): Oid =
   ## generates a new OID.
   proc rand(): cint {.importc: "rand", header: "<stdlib.h>", nodecl.}
-  proc gettime(dummy: ptr cint): cint {.importc: "time", header: "<time.h>".}
   proc srand(seed: cint) {.importc: "srand", header: "<stdlib.h>", nodecl.}
 
-  var t = gettime(nil)
+  var t = getTime().int32
 
   var i = int32(atomicInc(incr))
 
diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim
index 71991e35a..7720fb2a6 100644
--- a/lib/pure/ospaths.nim
+++ b/lib/pure/ospaths.nim
@@ -569,7 +569,7 @@ when declared(getEnv) or defined(nimscript):
       ## ``["exe", "cmd", "bat"]``, on Posix ``[""]``.
 
   proc findExe*(exe: string, followSymlinks: bool = true;
-                extensions=ExeExts): string {.
+                extensions: openarray[string]=ExeExts): string {.
     tags: [ReadDirEffect, ReadEnvEffect, ReadIOEffect].} =
     ## Searches for `exe` in the current working directory and then
     ## in directories listed in the ``PATH`` environment variable.
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index 0f37f8fe0..82a0c0c65 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -209,9 +209,16 @@ proc waitForExit*(p: Process, timeout: int = -1): int {.rtl,
   ##
   ## **Warning**: Be careful when using waitForExit for processes created without
   ## poParentStreams because they may fill output buffers, causing deadlock.
+  ##
+  ## On posix, if the process has exited because of a signal, 128 + signal
+  ## number will be returned.
+
 
 proc peekExitCode*(p: Process): int {.tags: [].}
   ## return -1 if the process is still running. Otherwise the process' exit code
+  ##
+  ## On posix, if the process has exited because of a signal, 128 + signal
+  ## number will be returned.
 
 proc inputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].}
   ## returns ``p``'s input stream for writing to.
@@ -679,6 +686,16 @@ elif not defined(useNimRtl):
     readIdx = 0
     writeIdx = 1
 
+  proc isExitStatus(status: cint): bool =
+    WIFEXITED(status) or WIFSIGNALED(status)
+
+  proc exitStatus(status: cint): cint =
+    if WIFSIGNALED(status):
+      # like the shell!
+      128 + WTERMSIG(status)
+    else:
+      WEXITSTATUS(status)
+
   proc envToCStringArray(t: StringTableRef): cstringArray =
     result = cast[cstringArray](alloc0((t.len + 1) * sizeof(cstring)))
     var i = 0
@@ -967,7 +984,7 @@ elif not defined(useNimRtl):
     var status : cint = 1
     ret = waitpid(p.id, status, WNOHANG)
     if ret == int(p.id):
-      if WIFEXITED(status):
+      if isExitStatus(status):
         p.exitStatus = status
         return false
       else:
@@ -990,7 +1007,9 @@ elif not defined(useNimRtl):
     import kqueue, times
 
     proc waitForExit(p: Process, timeout: int = -1): int =
-      if p.exitStatus != -3: return((p.exitStatus and 0xFF00) shr 8)
+      if p.exitStatus != -3:
+        return exitStatus(p.exitStatus)
+
       if timeout == -1:
         var status : cint = 1
         if waitpid(p.id, status, 0) < 0:
@@ -1041,7 +1060,7 @@ elif not defined(useNimRtl):
         finally:
           discard posix.close(kqFD)
 
-      result = ((p.exitStatus and 0xFF00) shr 8)
+      result = exitStatus(p.exitStatus)
   else:
     import times
 
@@ -1077,7 +1096,9 @@ elif not defined(useNimRtl):
       # ``waitPid`` fails if the process is not running anymore. But then
       # ``running`` probably set ``p.exitStatus`` for us. Since ``p.exitStatus`` is
       # initialized with -3, wrong success exit codes are prevented.
-      if p.exitStatus != -3: return((p.exitStatus and 0xFF00) shr 8)
+      if p.exitStatus != -3:
+        return exitStatus(p.exitStatus)
+
       if timeout == -1:
         var status : cint = 1
         if waitpid(p.id, status, 0) < 0:
@@ -1151,17 +1172,19 @@ elif not defined(useNimRtl):
             if sigprocmask(SIG_UNBLOCK, nmask, omask) == -1:
               raiseOSError(osLastError())
 
-      result = ((p.exitStatus and 0xFF00) shr 8)
+      result = exitStatus(p.exitStatus)
 
   proc peekExitCode(p: Process): int =
     var status = cint(0)
     result = -1
-    if p.exitStatus != -3: return((p.exitStatus and 0xFF00) shr 8)
+    if p.exitStatus != -3:
+      return exitStatus(p.exitStatus)
+
     var ret = waitpid(p.id, status, WNOHANG)
     if ret > 0:
-      if WIFEXITED(status):
+      if isExitStatus(status):
         p.exitStatus = status
-        result = (status and 0xFF00) shr 8
+        result = exitStatus(status)
 
   proc createStream(stream: var Stream, handle: var FileHandle,
                     fileMode: FileMode) =
@@ -1189,7 +1212,8 @@ elif not defined(useNimRtl):
 
   proc execCmd(command: string): int =
     when defined(linux):
-      result = csystem(command) shr 8
+      let tmp = csystem(command)
+      result = if tmp == -1: tmp else: exitStatus(tmp)
     else:
       result = csystem(command)
 
diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim
index ba745cfd3..c7e0ed1da 100644
--- a/lib/pure/uri.nim
+++ b/lib/pure/uri.nim
@@ -50,6 +50,7 @@ proc add*(url: var Url, a: Url) {.deprecated.} =
 proc parseAuthority(authority: string, result: var Uri) =
   var i = 0
   var inPort = false
+  var inIPv6 = false
   while true:
     case authority[i]
     of '@':
@@ -59,7 +60,14 @@ proc parseAuthority(authority: string, result: var Uri) =
       result.hostname.setLen(0)
       inPort = false
     of ':':
-      inPort = true
+      if inIPv6:
+        result.hostname.add(authority[i])
+      else:
+        inPort = true
+    of '[':
+      inIPv6 = true
+    of ']':
+      inIPv6 = false
     of '\0': break
     else:
       if inPort:
@@ -346,6 +354,17 @@ when isMainModule:
     doAssert($test == str)
 
   block:
+    # IPv6 address
+    let str = "foo://[::1]:1234/bar?baz=true&qux#quux"
+    let uri = parseUri(str)
+    doAssert uri.scheme == "foo"
+    doAssert uri.hostname == "::1"
+    doAssert uri.port == "1234"
+    doAssert uri.path == "/bar"
+    doAssert uri.query == "baz=true&qux"
+    doAssert uri.anchor == "quux"
+
+  block:
     let str = "urn:example:animal:ferret:nose"
     let test = parseUri(str)
     doAssert test.scheme == "urn"
diff --git a/lib/system.nim b/lib/system.nim
index 82d3bb7f7..9b41253cc 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -2016,6 +2016,12 @@ proc min*(x, y: float): float {.magic: "MinF64", noSideEffect.} =
   if x <= y: x else: y
 proc max*(x, y: float): float {.magic: "MaxF64", noSideEffect.} =
   if y <= x: x else: y
+
+proc min*[T](x, y: T): T =
+  if x <= y: x else: y
+
+proc max*[T](x, y: T): T =
+  if y <= x: x else: y
 {.pop.}
 
 proc clamp*[T](x, a, b: T): T =
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
index 9ef4a02f2..8a81a550a 100644
--- a/lib/system/jssys.nim
+++ b/lib/system/jssys.nim
@@ -172,7 +172,7 @@ proc raiseIndexError() {.compilerproc, noreturn.} =
 proc raiseFieldError(f: string) {.compilerproc, noreturn.} =
   raise newException(FieldError, f & " is not accessible")
 
-proc SetConstr() {.varargs, asmNoStackFrame, compilerproc.} =
+proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} =
   when defined(nimphp):
     asm """
       $args = func_get_args();
diff --git a/lib/upcoming/asyncdispatch.nim b/lib/upcoming/asyncdispatch.nim
index feee87bae..7c0497cc6 100644
--- a/lib/upcoming/asyncdispatch.nim
+++ b/lib/upcoming/asyncdispatch.nim
@@ -9,7 +9,7 @@
 
 include "system/inclrtl"
 
-import os, oids, tables, strutils, times, heapqueue, lists
+import os, oids, tables, strutils, times, heapqueue, lists, options
 
 import nativesockets, net, deques
 
@@ -325,68 +325,6 @@ when defined(windows) or defined(nimdoc):
     getAcceptExSockAddrs = cast[WSAPROC_GETACCEPTEXSOCKADDRS](fun)
     close(dummySock)
 
-  proc connect*(socket: AsyncFD, address: string, port: Port,
-    domain = nativesockets.AF_INET): Future[void] =
-    ## Connects ``socket`` to server at ``address:port``.
-    ##
-    ## Returns a ``Future`` which will complete when the connection succeeds
-    ## or an error occurs.
-    verifyPresence(socket)
-    var retFuture = newFuture[void]("connect")
-    # Apparently ``ConnectEx`` expects the socket to be initially bound:
-    var saddr: Sockaddr_in
-    saddr.sin_family = int16(toInt(domain))
-    saddr.sin_port = 0
-    saddr.sin_addr.s_addr = INADDR_ANY
-    if bindAddr(socket.SocketHandle, cast[ptr SockAddr](addr(saddr)),
-                  sizeof(saddr).SockLen) < 0'i32:
-      raiseOSError(osLastError())
-
-    var aiList = getAddrInfo(address, port, domain)
-    var success = false
-    var lastError: OSErrorCode
-    var it = aiList
-    while it != nil:
-      # "the OVERLAPPED structure must remain valid until the I/O completes"
-      # http://blogs.msdn.com/b/oldnewthing/archive/2011/02/02/10123392.aspx
-      var ol = PCustomOverlapped()
-      GC_ref(ol)
-      ol.data = CompletionData(fd: socket, cb:
-        proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
-          if not retFuture.finished:
-            if errcode == OSErrorCode(-1):
-              retFuture.complete()
-            else:
-              retFuture.fail(newException(OSError, osErrorMsg(errcode)))
-      )
-
-      var ret = connectEx(socket.SocketHandle, it.ai_addr,
-                          sizeof(Sockaddr_in).cint, nil, 0, nil,
-                          cast[POVERLAPPED](ol))
-      if ret:
-        # Request to connect completed immediately.
-        success = true
-        retFuture.complete()
-        # We don't deallocate ``ol`` here because even though this completed
-        # immediately poll will still be notified about its completion and it will
-        # free ``ol``.
-        break
-      else:
-        lastError = osLastError()
-        if lastError.int32 == ERROR_IO_PENDING:
-          # In this case ``ol`` will be deallocated in ``poll``.
-          success = true
-          break
-        else:
-          GC_unref(ol)
-          success = false
-      it = it.ai_next
-
-    freeAddrInfo(aiList)
-    if not success:
-      retFuture.fail(newException(OSError, osErrorMsg(lastError)))
-    return retFuture
-
   proc recv*(socket: AsyncFD, size: int,
              flags = {SocketFlag.SafeDisconn}): Future[string] =
     ## Reads **up to** ``size`` bytes from ``socket``. Returned future will
@@ -739,8 +677,8 @@ when defined(windows) or defined(nimdoc):
     var lpOutputBuf = newString(lpOutputLen)
     var dwBytesReceived: Dword
     let dwReceiveDataLength = 0.Dword # We don't want any data to be read.
-    let dwLocalAddressLength = Dword(sizeof(Sockaddr_in) + 16)
-    let dwRemoteAddressLength = Dword(sizeof(Sockaddr_in) + 16)
+    let dwLocalAddressLength = Dword(sizeof(Sockaddr_in6) + 16)
+    let dwRemoteAddressLength = Dword(sizeof(Sockaddr_in6) + 16)
 
     template failAccept(errcode) =
       if flags.isDisconnectionError(errcode):
@@ -770,12 +708,14 @@ when defined(windows) or defined(nimdoc):
                              dwLocalAddressLength, dwRemoteAddressLength,
                              addr localSockaddr, addr localLen,
                              addr remoteSockaddr, addr remoteLen)
-        register(clientSock.AsyncFD)
-        # TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186
-        retFuture.complete(
-          (address: $inet_ntoa(cast[ptr Sockaddr_in](remoteSockAddr).sin_addr),
-          client: clientSock.AsyncFD)
-        )
+        try:
+          let address = getAddrString(remoteSockAddr)
+          register(clientSock.AsyncFD)
+          retFuture.complete((address: address, client: clientSock.AsyncFD))
+        except:
+          # getAddrString may raise
+          clientSock.close()
+          retFuture.fail(getCurrentException())
 
     var ol = PCustomOverlapped()
     GC_ref(ol)
@@ -808,20 +748,6 @@ when defined(windows) or defined(nimdoc):
 
     return retFuture
 
-  proc newAsyncNativeSocket*(domain, sockType, protocol: cint): AsyncFD =
-    ## Creates a new socket and registers it with the dispatcher implicitly.
-    result = newNativeSocket(domain, sockType, protocol).AsyncFD
-    result.SocketHandle.setBlocking(false)
-    register(result)
-
-  proc newAsyncNativeSocket*(domain: Domain = nativesockets.AF_INET,
-                             sockType: SockType = SOCK_STREAM,
-                             protocol: Protocol = IPPROTO_TCP): AsyncFD =
-    ## Creates a new socket and registers it with the dispatcher implicitly.
-    result = newNativeSocket(domain, sockType, protocol).AsyncFD
-    result.SocketHandle.setBlocking(false)
-    register(result)
-
   proc closeSocket*(socket: AsyncFD) =
     ## Closes a socket and ensures that it is unregistered.
     socket.SocketHandle.close()
@@ -1159,23 +1085,6 @@ else:
     var data = newAsyncData()
     p.selector.registerHandle(fd.SocketHandle, {}, data)
 
-  proc newAsyncNativeSocket*(domain: cint, sockType: cint,
-                             protocol: cint): AsyncFD =
-    result = newNativeSocket(domain, sockType, protocol).AsyncFD
-    result.SocketHandle.setBlocking(false)
-    when defined(macosx):
-      result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
-    register(result)
-
-  proc newAsyncNativeSocket*(domain: Domain = AF_INET,
-                             sockType: SockType = SOCK_STREAM,
-                             protocol: Protocol = IPPROTO_TCP): AsyncFD =
-    result = newNativeSocket(domain, sockType, protocol).AsyncFD
-    result.SocketHandle.setBlocking(false)
-    when defined(macosx):
-      result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
-    register(result)
-
   proc closeSocket*(sock: AsyncFD) =
     let disp = getGlobalDispatcher()
     disp.selector.unregister(sock.SocketHandle)
@@ -1331,50 +1240,6 @@ else:
     # Callback queue processing
     processPendingCallbacks(p)
 
-  proc connect*(socket: AsyncFD, address: string, port: Port,
-    domain = AF_INET): Future[void] =
-    var retFuture = newFuture[void]("connect")
-
-    proc cb(fd: AsyncFD): bool =
-      var ret = SocketHandle(fd).getSockOptInt(cint(SOL_SOCKET), cint(SO_ERROR))
-      if ret == 0:
-          # We have connected.
-          retFuture.complete()
-          return true
-      elif ret == EINTR:
-          # interrupted, keep waiting
-          return false
-      else:
-          retFuture.fail(newException(OSError, osErrorMsg(OSErrorCode(ret))))
-          return true
-
-    assert getSockDomain(socket.SocketHandle) == domain
-    var aiList = getAddrInfo(address, port, domain)
-    var success = false
-    var lastError: OSErrorCode
-    var it = aiList
-    while it != nil:
-      var ret = connect(socket.SocketHandle, it.ai_addr, it.ai_addrlen.Socklen)
-      if ret == 0:
-        # Request to connect completed immediately.
-        success = true
-        retFuture.complete()
-        break
-      else:
-        lastError = osLastError()
-        if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
-          success = true
-          addWrite(socket, cb)
-          break
-        else:
-          success = false
-      it = it.ai_next
-
-    freeAddrInfo(aiList)
-    if not success:
-      retFuture.fail(newException(OSError, osErrorMsg(lastError)))
-    return retFuture
-
   proc recv*(socket: AsyncFD, size: int,
              flags = {SocketFlag.SafeDisconn}): Future[string] =
     var retFuture = newFuture[string]("recv")
@@ -1568,9 +1433,14 @@ else:
           else:
             retFuture.fail(newException(OSError, osErrorMsg(lastError)))
       else:
-        register(client.AsyncFD)
-        retFuture.complete((getAddrString(cast[ptr SockAddr](addr sockAddress)),
-                            client.AsyncFD))
+        try:
+          let address = getAddrString(cast[ptr SockAddr](addr sockAddress))
+          register(client.AsyncFD)
+          retFuture.complete((address, client.AsyncFD))
+        except:
+          # getAddrString may raise
+          client.close()
+          retFuture.fail(getCurrentException())
     addRead(socket, cb)
     return retFuture
 
@@ -1623,6 +1493,9 @@ else:
     data.readList.add(cb)
     p.selector.registerEvent(SelectEvent(ev), data)
 
+# Common procedures between current and upcoming asyncdispatch
+include includes.asynccommon
+
 proc sleepAsync*(ms: int): Future[void] =
   ## Suspends the execution of the current async procedure for the next
   ## ``ms`` milliseconds.
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index 1f8dc9ad6..164499543 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -495,7 +495,7 @@ type
     ai_family*: cint        ## Address family of socket.
     ai_socktype*: cint      ## Socket type.
     ai_protocol*: cint      ## Protocol of socket.
-    ai_addrlen*: int        ## Length of socket address.
+    ai_addrlen*: csize        ## Length of socket address.
     ai_canonname*: cstring  ## Canonical name of service location.
     ai_addr*: ptr SockAddr ## Socket address of socket.
     ai_next*: ptr AddrInfo ## Pointer to next in list.
@@ -803,6 +803,7 @@ const
   SIO_GET_EXTENSION_FUNCTION_POINTER* = WSAIORW(IOC_WS2,6).DWORD
   SO_UPDATE_ACCEPT_CONTEXT* = 0x700B
   AI_V4MAPPED* = 0x0008
+  AF_UNSPEC* = 0
   AF_INET* = 2
   AF_INET6* = 23
 
diff --git a/readme.md b/readme.md
index 34208eb5e..30cc14079 100644
--- a/readme.md
+++ b/readme.md
@@ -1,4 +1,4 @@
-# ![Logo][image-nim-logo] Nim [![Build Status][badge-nim-travisci]][nim-travisci]
+# <img src="https://raw.githubusercontent.com/nim-lang/assets/master/Art/logo-crown.png" height="28px"/> Nim [![Build Status][badge-nim-travisci]][nim-travisci]
 
 This repository contains the Nim compiler, Nim's stdlib, tools and documentation.
 For more information about Nim, including downloads and documentation for
@@ -171,5 +171,4 @@ Copyright © 2006-2017 Andreas Rumpf, all rights reserved.
 [badge-nim-gratipay]: https://img.shields.io/gratipay/team/nim.svg?style=flat-square
 [badge-nim-bountysource]: https://img.shields.io/bountysource/team/nim/activity.svg?style=flat-square
 [badge-nim-bitcoin]: https://img.shields.io/badge/bitcoin-1BXfuKM2uvoD6mbx4g5xM3eQhLzkCK77tJ-D69134.svg?style=flat-square
-[image-nim-logo]: https://images1-focus-opensocial.googleusercontent.com/gadgets/proxy?url=https://raw.githubusercontent.com/nim-lang/assets/master/Art/logo-crown.png&container=focus&resize_w=36&refresh=21600
 [pull-request-instructions]: https://help.github.com/articles/using-pull-requests/
diff --git a/tests/async/tasyncdial.nim b/tests/async/tasyncdial.nim
new file mode 100644
index 000000000..d70e14020
--- /dev/null
+++ b/tests/async/tasyncdial.nim
@@ -0,0 +1,53 @@
+discard """
+  file: "tasyncdial.nim"
+  output: '''
+OK AF_INET
+OK AF_INET6
+'''
+"""
+
+import
+  nativesockets, os, asyncdispatch
+
+proc setupServerSocket(hostname: string, port: Port, domain: Domain): AsyncFD =
+  ## Creates a socket, binds it to the specified address, and starts listening for connecitons.
+  ## Registers the descriptor with the dispatcher of the current thread
+  ## Raises OSError in case of an error.
+  let fd = newNativeSocket(domain)
+  setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1)
+  var aiList = getAddrInfo(hostname, port, domain)
+  if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
+    freeAddrInfo(aiList)
+    raiseOSError(osLastError())
+  freeAddrInfo(aiList)
+  if listen(fd) != 0:
+    raiseOSError(osLastError())
+  setBlocking(fd, false)
+  result = fd.AsyncFD
+  register(result)
+
+proc doTest(domain: static[Domain]) {.async.} =
+  const
+    testHost = when domain == Domain.AF_INET6: "::1" else: "127.0.0.1"
+    testPort = Port(17384)
+  let serverFd = setupServerSocket(testHost, testPort, domain)
+  let acceptFut = serverFd.accept()
+  let clientFdFut = dial(testHost, testPort)
+
+  let serverClientFd = await acceptFut
+  serverFd.closeSocket()
+
+  let clientFd = await clientFdFut
+
+  let recvFut = serverClientFd.recv(2)
+  await clientFd.send("Hi")
+  let msg = await recvFut
+
+  serverClientFd.closeSocket()
+  clientFd.closeSocket()
+
+  if msg == "Hi":
+    echo "OK ", domain
+
+waitFor(doTest(Domain.AF_INET))
+waitFor(doTest(Domain.AF_INET6))
diff --git a/tests/osproc/texitsignal.nim b/tests/osproc/texitsignal.nim
new file mode 100644
index 000000000..c0bed70ee
--- /dev/null
+++ b/tests/osproc/texitsignal.nim
@@ -0,0 +1,36 @@
+discard """
+  output: '''true
+true'''
+  targets: "c"
+"""
+
+import os, osproc
+when not defined(windows):
+  import posix
+
+# Checks that the environment is passed correctly in startProcess
+# To do that launches a copy of itself with a new environment.
+
+if paramCount() == 0:
+  # Parent process
+
+  let p = startProcess(
+    getAppFilename(),
+    args = @["child"],
+    options = {poStdErrToStdOut, poUsePath, poParentStreams}
+  )
+
+  echo p.running()
+
+  p.kill()
+
+  when defined(windows):
+    # windows kill happens using TerminateProcess(h, 0), so we should get a
+    # 0 here
+    echo p.waitForExit() == 0
+  else:
+    # on posix (non-windows), kill sends SIGKILL
+    echo p.waitForExit() == 128 + SIGKILL
+
+else:
+  sleep(5000)  # should get killed before this
\ No newline at end of file
diff --git a/tests/parser/twrongcmdsyntax.nim b/tests/parser/twrongcmdsyntax.nim
new file mode 100644
index 000000000..affe72c34
--- /dev/null
+++ b/tests/parser/twrongcmdsyntax.nim
@@ -0,0 +1,6 @@
+discard """
+  errormsg: '''identifier expected, but found 'echo 4'''
+  line: 6
+"""
+
+echo 4 +2
diff --git a/tests/stdlib/thttpclient.nim b/tests/stdlib/thttpclient.nim
index 62c1ebee7..40324d92a 100644
--- a/tests/stdlib/thttpclient.nim
+++ b/tests/stdlib/thttpclient.nim
@@ -1,11 +1,13 @@
 discard """
   cmd: "nim c --threads:on -d:ssl $file"
+  exitcode: 0
+  output: "OK"
 """
 
 import strutils
 from net import TimeoutError
 
-import httpclient, asyncdispatch
+import nativesockets, os, httpclient, asyncdispatch
 
 const manualTests = false
 
@@ -112,6 +114,40 @@ proc syncTest() =
   except:
     doAssert false, "TimeoutError should have been raised."
 
-syncTest()
+proc makeIPv6HttpServer(hostname: string, port: Port): AsyncFD =
+  let fd = newNativeSocket(AF_INET6)
+  setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1)
+  var aiList = getAddrInfo(hostname, port, AF_INET6)
+  if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
+    freeAddrInfo(aiList)
+    raiseOSError(osLastError())
+  freeAddrInfo(aiList)
+  if listen(fd) != 0:
+    raiseOSError(osLastError())
+  setBlocking(fd, false)
+
+  var serverFd = fd.AsyncFD
+  register(serverFd)
+  result = serverFd
+
+  proc onAccept(fut: Future[AsyncFD]) {.gcsafe.} =
+    if not fut.failed:
+      let clientFd = fut.read()
+      clientFd.send("HTTP/1.1 200 OK\r\LContent-Length: 0\r\LConnection: Closed\r\L\r\L").callback = proc() =
+        clientFd.closeSocket()
+      serverFd.accept().callback = onAccept
+  serverFd.accept().callback = onAccept
+
+proc ipv6Test() =
+  var client = newAsyncHttpClient()
+  let serverFd = makeIPv6HttpServer("::1", Port(18473))
+  var resp = waitFor client.request("http://[::1]:18473/")
+  doAssert(resp.status == "200 OK")
+  serverFd.closeSocket()
+  client.close()
 
+syncTest()
 waitFor(asyncTest())
+ipv6Test()
+
+echo "OK"
diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim
index 74b0d4dc3..323b3e1ee 100644
--- a/tests/stdlib/tjsonmacro.nim
+++ b/tests/stdlib/tjsonmacro.nim
@@ -159,11 +159,11 @@ when isMainModule:
         name: string
         age: int
 
-      Data = object
+      Data1 = object # TODO: Codegen bug when changed to ``Data``.
         person: Person
         list: seq[int]
 
-    var data = to(jsonNode, Data)
+    var data = to(jsonNode, Data1)
     doAssert data.person.name == "Nimmer"
     doAssert data.person.age == 21
     doAssert data.list == @[1, 2, 3, 4]
@@ -182,4 +182,48 @@ when isMainModule:
     }
 
     var result = to(node, TestEnum)
-    doAssert result.field == Bar
\ No newline at end of file
+    doAssert result.field == Bar
+
+  # Test ref type in field.
+  block:
+    var jsonNode = parseJson("""
+      {
+        "person": {
+          "name": "Nimmer",
+          "age": 21
+        },
+        "list": [1, 2, 3, 4]
+      }
+    """)
+
+    type
+      Person = ref object
+        name: string
+        age: int
+
+      Data = object
+        person: Person
+        list: seq[int]
+
+    var data = to(jsonNode, Data)
+    doAssert data.person.name == "Nimmer"
+    doAssert data.person.age == 21
+    doAssert data.list == @[1, 2, 3, 4]
+
+    jsonNode = parseJson("""
+      {
+        "person": null,
+        "list": [1, 2, 3, 4]
+      }
+    """)
+    data = to(jsonNode, Data)
+    doAssert data.person.isNil
+
+  block:
+    type
+      FooBar = object
+        field: float
+
+    let x = parseJson("""{ "field": 5}""")
+    let data = to(x, FooBar)
+    doAssert data.field == 5.0
\ No newline at end of file
diff --git a/tests/stdlib/tnetdial.nim b/tests/stdlib/tnetdial.nim
new file mode 100644
index 000000000..da6088d70
--- /dev/null
+++ b/tests/stdlib/tnetdial.nim
@@ -0,0 +1,60 @@
+discard """
+  cmd: "nim c --threads:on $file"
+  exitcode: 0
+  output: "OK"
+"""
+
+import os, net, nativesockets, asyncdispatch
+
+## Test for net.dial
+
+const port = Port(28431)
+
+proc initIPv6Server(hostname: string, port: Port): AsyncFD =
+  let fd = newNativeSocket(AF_INET6)
+  setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1)
+  var aiList = getAddrInfo(hostname, port, AF_INET6)
+  if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
+    freeAddrInfo(aiList)
+    raiseOSError(osLastError())
+  freeAddrInfo(aiList)
+  if listen(fd) != 0:
+    raiseOSError(osLastError())
+  setBlocking(fd, false)
+
+  var serverFd = fd.AsyncFD
+  register(serverFd)
+  result = serverFd
+
+# Since net.dial is synchronous, we use main thread to setup server,
+# and dial to it from another thread.
+
+proc testThread() {.thread.} =
+  let fd = net.dial("::1", port)
+  var s = newString(5)
+  doAssert fd.recv(addr s[0], 5) == 5
+  if s == "Hello":
+    echo "OK"
+  fd.close()
+
+proc test() =
+  var t: Thread[void]
+  createThread(t, testThread)
+
+  let serverFd = initIPv6Server("::1", port)
+  var done = false
+
+  serverFd.accept().callback = proc(fut: Future[AsyncFD]) =
+    serverFd.closeSocket()
+    if not fut.failed:
+      let fd = fut.read()
+      fd.send("Hello").callback = proc() =
+        fd.closeSocket()
+        done = true
+
+  while not done:
+    poll()
+
+  joinThread(t)
+
+test()
diff --git a/tests/tuples/tunpack_asgn.nim b/tests/tuples/tunpack_asgn.nim
index a48fcff5d..1dc7ff074 100644
--- a/tests/tuples/tunpack_asgn.nim
+++ b/tests/tuples/tunpack_asgn.nim
@@ -21,6 +21,8 @@ proc pg[T](x, y: var T) =
 
 # test as a top level statement:
 var x, y, a, b: int
+# test for regression:
+(x, y) = (1, 2)
 (x, y) = fooBar()
 
 echo x, " ", y
diff --git a/tests/tuples/tuple_subscript.nim b/tests/tuples/tuple_subscript.nim
new file mode 100644
index 000000000..021793dc3
--- /dev/null
+++ b/tests/tuples/tuple_subscript.nim
@@ -0,0 +1,40 @@
+discard """
+  output: '''5
+5
+str2
+str2
+4'''
+"""
+
+proc`[]` (t: tuple, key: string): string =
+  for name, field in fieldPairs(t):
+    if name == key: 
+      return $field
+  return ""
+
+
+proc`[]` [A,B](t: tuple, key: string, op: (proc(x: A): B)): B =
+  for name, field in fieldPairs(t):
+    when field is A:
+      if name == key: 
+        return op(field)
+
+proc`[]=`[T](t: var tuple, key: string, val: T) =
+  for name, field in fieldPairs(t):
+    when field is T:
+      if name == key: 
+        field = val
+
+var tt = (a: 1, b: "str1")
+
+# test built in operator
+tt[0] = 5
+echo tt[0] 
+echo `[]`(tt, 0)
+
+
+# test overloaded operator
+tt["b"] = "str2"
+echo tt["b"] 
+echo `[]`(tt, "b")
+echo tt["b", proc(s: string) : int = s.len]
\ No newline at end of file
diff --git a/web/news/e031_version_0_16_2.rst b/web/news/e031_version_0_16_2.rst
index fd12bb822..63884700f 100644
--- a/web/news/e031_version_0_16_2.rst
+++ b/web/news/e031_version_0_16_2.rst
@@ -13,6 +13,9 @@ Changelog
 Changes affecting backwards compatibility
 -----------------------------------------
 
+- There are now two different HTTP response types, ``Response`` and
+  ``AsyncResponse``. ``AsyncResponse``'s ``body`` accessor returns a
+  ``Future[string]``!
 - ``httpclient.request`` now respects ``maxRedirects`` option. Previously
   redirects were handled only by ``get`` and ``post`` procs.
 - The IO routines now raise ``EOFError`` for the "end of file" condition.
@@ -56,12 +59,17 @@ Changes affecting backwards compatibility
   checks. When fields within case objects are initialiazed, the compiler will
   now demand that the respective discriminator field has a matching known
   compile-time value.
+- On posix, the results of `waitForExit`, `peekExitCode`, `execCmd` will return
+  128 + signal number if the application terminates via signal.
 
 Library Additions
 -----------------
 
 - Added ``system.onThreadDestruction``.
-
+- Added ``dial`` procedure to networking modules: ``net``, ``asyncdispatch``,
+  ``asyncnet``. It merges socket creation, address resolution, and connection
+  into single step. When using ``dial``, you don't have to worry about
+  IPv4 vs IPv6 problem. ``httpclient`` now supports IPv6.
 
 Tool Additions
 --------------