summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim6
-rw-r--r--compiler/ccgcalls.nim20
-rw-r--r--compiler/ccgexprs.nim4
-rw-r--r--compiler/destroyer.nim177
-rw-r--r--compiler/dfa.nim2
-rw-r--r--compiler/evaltempl.nim14
-rw-r--r--compiler/lambdalifting.nim5
-rw-r--r--compiler/lookups.nim2
-rw-r--r--compiler/sem.nim11
-rw-r--r--compiler/semexprs.nim4
-rw-r--r--compiler/semfold.nim8
-rw-r--r--compiler/seminst.nim2
-rw-r--r--compiler/semmagic.nim2
-rw-r--r--compiler/semstmts.nim47
-rw-r--r--compiler/semtypes.nim10
-rw-r--r--koch.nim2
-rw-r--r--lib/pure/asyncdispatch.nim213
-rw-r--r--lib/pure/includes/asynccommon.nim211
-rw-r--r--tests/destructor/tmatrix.nim22
-rw-r--r--tests/destructor/tmove_objconstr.nim47
-rw-r--r--tests/errmsgs/t9908_01.nim10
-rw-r--r--tests/errmsgs/t9908_02.nim10
-rw-r--r--tests/misc/tsizeof2.nim2
-rw-r--r--tests/modules/m9627/a.nim1
-rw-r--r--tests/modules/m9627/b.nim1
-rw-r--r--tests/modules/t9627.nim7
-rw-r--r--tests/pragmas/tused.nim6
-rw-r--r--tests/template/tparams_gensymed.nim40
28 files changed, 546 insertions, 340 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 40a05e6bf..0247acb03 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -1087,9 +1087,6 @@ proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
   result.id = getID()
   when debugIds:
     registerId(result)
-  #if result.id == 77131:
-  #  writeStacktrace()
-  #  echo name.s
 
 proc isMetaType*(t: PType): bool =
   return t.kind in tyMetaTypes or
@@ -1261,6 +1258,9 @@ proc `$`*(x: TLockLevel): string =
   elif x.ord == UnknownLockLevel.ord: result = "<unknown>"
   else: result = $int16(x)
 
+proc `$`*(s: PSym): string =
+  result = s.name.s & "@" & $s.id
+
 proc newType*(kind: TTypeKind, owner: PSym): PType =
   new(result)
   result.kind = kind
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index b23cd598e..d177e1f88 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -63,26 +63,6 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
     add(pl, ~");$n")
     line(p, cpsStmts, pl)
 
-proc isInCurrentFrame(p: BProc, n: PNode): bool =
-  # checks if `n` is an expression that refers to the current frame;
-  # this does not work reliably because of forwarding + inlining can break it
-  case n.kind
-  of nkSym:
-    if n.sym.kind in {skVar, skResult, skTemp, skLet} and p.prc != nil:
-      result = p.prc.id == n.sym.owner.id
-  of nkDotExpr, nkBracketExpr:
-    if skipTypes(n.sons[0].typ, abstractInst).kind notin {tyVar,tyLent,tyPtr,tyRef}:
-      result = isInCurrentFrame(p, n.sons[0])
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
-    result = isInCurrentFrame(p, n.sons[1])
-  of nkHiddenDeref, nkDerefExpr:
-    # what about: var x = addr(y); callAsOpenArray(x[])?
-    # *shrug* ``addr`` is unsafe anyway.
-    result = false
-  of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
-    result = isInCurrentFrame(p, n.sons[0])
-  else: discard
-
 proc genBoundsCheck(p: BProc; arr, a, b: TLoc)
 
 proc openArrayLoc(p: BProc, n: PNode): Rope =
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 59ef05f9c..cab2c78f5 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -850,7 +850,6 @@ proc genUncheckedArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
   var a, b: TLoc
   initLocExpr(p, x, a)
   initLocExpr(p, y, b)
-  var ty = skipTypes(a.t, abstractVarRange + abstractPtrs + tyUserTypeClasses)
   d.inheritLocation(a)
   putIntoDest(p, d, n, ropecg(p.module, "$1[$2]", rdLoc(a), rdCharLoc(b)),
               a.storage)
@@ -884,7 +883,6 @@ proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) =
   var a, b: TLoc
   initLocExpr(p, x, a)
   initLocExpr(p, y, b)
-  var ty = skipTypes(a.t, abstractVarRange)
   inheritLocation(d, a)
   putIntoDest(p, d, n,
               ropecg(p.module, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
@@ -1402,7 +1400,6 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
   else:
     var i: TLoc
     getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i)
-    let oldCode = p.s(cpsStmts)
     linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",  i.r, L.rope)
     initLoc(elem, locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap)
     elem.r = ropecg(p.module, "$1$3[$2]", rdLoc(d), rdLoc(i), dataField(p))
@@ -2576,7 +2573,6 @@ proc genConstObjConstr(p: BProc; n: PNode): Rope =
 proc genConstSimpleList(p: BProc, n: PNode): Rope =
   var length = sonsLen(n)
   result = rope("{")
-  let t = n.typ.skipTypes(abstractInst)
   for i in countup(0, length - 2):
     addf(result, "$1,$n", [genNamedConstExpr(p, n.sons[i])])
   if length > 0:
diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim
index 51ad26f2c..407204e51 100644
--- a/compiler/destroyer.nim
+++ b/compiler/destroyer.nim
@@ -116,7 +116,7 @@ Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently
 
 import
   intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
-  strutils, options, dfa, lowerings, tables, modulegraphs,
+  strutils, options, dfa, lowerings, tables, modulegraphs, msgs,
   lineinfos, parampatterns
 
 const
@@ -127,20 +127,11 @@ type
     owner: PSym
     g: ControlFlowGraph
     jumpTargets: IntSet
-    tmpObj: PType
-    tmp: PSym
     destroys, topLevelVars: PNode
-    toDropBit: Table[int, PSym]
     graph: ModuleGraph
     emptyNode: PNode
     otherRead: PNode
 
-proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode =
-  # XXX why are temps fields in an object here?
-  let f = newSym(skField, getIdent(c.graph.cache, ":d" & $c.tmpObj.n.len), c.owner, info)
-  f.typ = typ
-  rawAddField c.tmpObj, f
-  result = rawDirectAccess(c.tmp, f)
 
 proc isHarmlessVar*(s: PSym; c: Con): bool =
   # 's' is harmless if it used only once and its
@@ -329,22 +320,11 @@ proc genDestroy(c: Con; t: PType; dest: PNode): PNode =
 proc addTopVar(c: var Con; v: PNode) =
   c.topLevelVars.add newTree(nkIdentDefs, v, c.emptyNode, c.emptyNode)
 
-proc dropBit(c: var Con; s: PSym): PSym =
-  result = c.toDropBit.getOrDefault(s.id)
-  assert result != nil
-
-proc registerDropBit(c: var Con; s: PSym) =
-  let result = newSym(skTemp, getIdent(c.graph.cache, s.name.s & "_AliveBit"), c.owner, s.info)
-  result.typ = getSysType(c.graph, s.info, tyBool)
-  let trueVal = newIntTypeNode(nkIntLit, 1, result.typ)
-  c.topLevelVars.add newTree(nkIdentDefs, newSymNode result, c.emptyNode, trueVal)
-  c.toDropBit[s.id] = result
-  # generate:
-  #  if not sinkParam_AliveBit: `=destroy`(sinkParam)
-  let t = s.typ.skipTypes({tyGenericInst, tyAlias, tySink})
-  if t.destructor != nil:
-    c.destroys.add newTree(nkIfStmt,
-      newTree(nkElifBranch, newSymNode result, genDestroy(c, t, newSymNode s)))
+proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode =
+  let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.owner, info)
+  sym.typ = typ
+  result = newSymNode(sym)
+  c.addTopVar(result)
 
 proc p(n: PNode; c: var Con): PNode
 
@@ -355,16 +335,6 @@ template recurse(n, dest) =
 proc isSinkParam(s: PSym): bool {.inline.} =
   result = s.kind == skParam and s.typ.kind == tySink
 
-proc destructiveMoveSink(n: PNode; c: var Con): PNode =
-  # generate:  (chckMove(sinkParam_AliveBit); sinkParam_AliveBit = false; sinkParam)
-  result = newNodeIT(nkStmtListExpr, n.info, n.typ)
-  let bit = newSymNode dropBit(c, n.sym)
-  if optMoveCheck in c.owner.options:
-    result.add callCodegenProc(c.graph, "chckMove", bit.info, bit)
-  result.add newTree(nkAsgn, bit,
-    newIntTypeNode(nkIntLit, 0, getSysType(c.graph, n.info, tyBool)))
-  result.add n
-
 proc genMagicCall(n: PNode; c: var Con; magicname: string; m: TMagic): PNode =
   result = newNodeI(nkCall, n.info)
   result.add(newSymNode(createMagic(c.graph, magicname, m)))
@@ -395,6 +365,12 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode =
   result.add genWasMoved(n, c)
   result.add tempAsNode
 
+proc sinkParamIsLastReadCheck(c: var Con, s: PNode) = 
+  assert s.kind == nkSym and s.sym.kind == skParam
+  if not isLastRead(s, c):
+     localError(c.graph.config, c.otherRead.info, "sink parameter `" & $s.sym.name.s &
+         "` is already consumed at " & toFileLineCol(c. graph.config, s.info))
+
 proc passCopyToSink(n: PNode; c: var Con): PNode =
   result = newNodeIT(nkStmtListExpr, n.info, n.typ)
   let tmp = getTemp(c, n.typ, n.info)
@@ -411,6 +387,11 @@ proc passCopyToSink(n: PNode; c: var Con): PNode =
   result.add tmp
 
 proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
+  template pArgIfTyped(arg_part: PNode): PNode =
+    # typ is nil if we are in if/case expr branch with noreturn
+    if arg_part.typ == nil: p(arg_part, c)
+    else: pArg(arg_part, c, isSink)
+
   if isSink:
     if arg.kind in nkCallKinds:
       # recurse but skip the call expression in order to prevent
@@ -421,17 +402,53 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
       result.add arg[0]
       for i in 1..<arg.len:
         result.add pArg(arg[i], c, i < L and parameters[i].kind == tySink)
-    elif arg.kind in {nkObjConstr, nkCharLit..nkFloat128Lit}:
+    elif arg.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkBracket, nkCharLit..nkFloat128Lit}:
       discard "object construction to sink parameter: nothing to do"
       result = arg
+    elif arg.kind == nkSym and isSinkParam(arg.sym):
+      # Sinked params can be consumed only once. We need to reset the memory
+      # to disable the destructor which we have not elided
+      sinkParamIsLastReadCheck(c, arg)
+      result = destructiveMoveVar(arg, c)
     elif arg.kind == nkSym and arg.sym.kind in InterestingSyms and isLastRead(arg, c):
-      # if x is a variable and it its last read we eliminate its
-      # destructor invokation, but don't. We need to reset its memory
-      # to disable its destructor which we have not elided:
+      # it is the last read, can be sinked. We need to reset the memory
+      # to disable the destructor which we have not elided
       result = destructiveMoveVar(arg, c)
-    elif arg.kind == nkSym and isSinkParam(arg.sym):
-      # mark the sink parameter as used:
-      result = destructiveMoveSink(arg, c)
+    elif arg.kind in {nkBlockExpr, nkBlockStmt}:
+      result = copyNode(arg)
+      result.add arg[0]
+      result.add pArg(arg[1], c, isSink)
+    elif arg.kind == nkStmtListExpr:
+      result = copyNode(arg)
+      for i in 0..arg.len-2:
+        result.add p(arg[i], c)
+      result.add pArg(arg[^1], c, isSink)
+    elif arg.kind in {nkIfExpr, nkIfStmt}:
+      result = copyNode(arg)
+      for i in 0..<arg.len:
+        var branch = copyNode(arg[i])
+        if arg[i].kind in {nkElifBranch, nkElifExpr}:   
+          branch.add p(arg[i][0], c)
+          branch.add pArgIfTyped(arg[i][1])
+        else:
+          branch.add pArgIfTyped(arg[i][0])
+        result.add branch
+    elif arg.kind == nkCaseStmt:
+      result = copyNode(arg)
+      result.add p(arg[0], c)
+      for i in 1..<arg.len:
+        var branch: PNode
+        if arg[i].kind == nkOfbranch:
+          branch = arg[i] # of branch conditions are constants
+          branch[^1] = pArgIfTyped(arg[i][^1])
+        elif arg[i].kind in {nkElifBranch, nkElifExpr}:
+          branch = copyNode(arg[i])   
+          branch.add p(arg[i][0], c)
+          branch.add pArgIfTyped(arg[i][1])
+        else:
+          branch = copyNode(arg[i]) 
+          branch.add pArgIfTyped(arg[i][0])
+        result.add branch     
     else:
       # an object that is not temporary but passed to a 'sink' parameter
       # results in a copy.
@@ -440,6 +457,11 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
     result = p(arg, c)
 
 proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
+  template moveOrCopyIfTyped(ri_part: PNode): PNode =
+    # typ is nil if we are in if/case expr branch with noreturn
+    if ri_part.typ == nil: p(ri_part, c)
+    else: moveOrCopy(dest, ri_part, c)
+
   case ri.kind
   of nkCallKinds:
     result = genSink(c, dest.typ, dest, ri)
@@ -454,7 +476,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
     result.add ri2
   of nkBracketExpr:
     if ri[0].kind == nkSym and isUnpackedTuple(ri[0].sym):
-      # unpacking of tuple: move out the elements
+      # unpacking of tuple: move out the elements 
       result = genSink(c, dest.typ, dest, ri)
     else:
       result = genCopy(c, dest.typ, dest, ri)
@@ -464,6 +486,45 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
     for i in 0..ri.len-2:
       result.add p(ri[i], c)
     result.add moveOrCopy(dest, ri[^1], c)
+  of nkBlockExpr, nkBlockStmt:
+    result = newNodeI(nkBlockStmt, ri.info)
+    result.add ri[0] ## add label
+    result.add moveOrCopy(dest, ri[1], c)
+  of nkIfExpr, nkIfStmt:
+    result = newNodeI(nkIfStmt, ri.info)
+    for i in 0..<ri.len:
+      var branch = copyNode(ri[i])
+      if ri[i].kind in {nkElifBranch, nkElifExpr}:
+        branch.add p(ri[i][0], c)
+        branch.add moveOrCopyIfTyped(ri[i][1])
+      else:
+        branch.add moveOrCopyIfTyped(ri[i][0])
+      result.add branch
+  of nkCaseStmt:
+    result = newNodeI(nkCaseStmt, ri.info)
+    result.add p(ri[0], c)
+    for i in 1..<ri.len:
+      var branch: PNode
+      if ri[i].kind == nkOfbranch:
+        branch = ri[i] # of branch conditions are constants
+        branch[^1] = moveOrCopyIfTyped(ri[i][^1])
+      elif ri[i].kind in {nkElifBranch, nkElifExpr}:
+        branch = copyNode(ri[i])   
+        branch.add p(ri[i][0], c)
+        branch.add moveOrCopyIfTyped(ri[i][1])
+      else:
+        branch = copyNode(ri[i]) 
+        branch.add moveOrCopyIfTyped(ri[i][0])
+      result.add branch
+  of nkBracket:
+    # array constructor
+    result = genSink(c, dest.typ, dest, ri)
+    let ri2 = copyTree(ri)
+    for i in 0..<ri.len:
+      # everything that is passed to an array constructor is consumed,
+      # so these all act like 'sink' parameters:
+      ri2[i] = pArg(ri[i], c, isSink = true)
+    result.add ri2
   of nkObjConstr:
     result = genSink(c, dest.typ, dest, ri)
     let ri2 = copyTree(ri)
@@ -484,14 +545,17 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
         ri2[i] = pArg(ri[i], c, isSink = true)
     result.add ri2
   of nkSym:
-    if ri.sym.kind != skParam and isLastRead(ri, c):
+    if isSinkParam(ri.sym):
       # Rule 3: `=sink`(x, z); wasMoved(z)
+      sinkParamIsLastReadCheck(c, ri)
       var snk = genSink(c, dest.typ, dest, ri)
-      snk.add p(ri, c)
+      snk.add ri
+      result = newTree(nkStmtList, snk, genMagicCall(ri, c, "wasMoved", mWasMoved))   
+    elif ri.sym.kind != skParam and isLastRead(ri, c):
+      # Rule 3: `=sink`(x, z); wasMoved(z)
+      var snk = genSink(c, dest.typ, dest, ri)
+      snk.add ri
       result = newTree(nkStmtList, snk, genMagicCall(ri, c, "wasMoved", mWasMoved))
-    elif isSinkParam(ri.sym):
-      result = genSink(c, dest.typ, dest, ri)
-      result.add destructiveMoveSink(ri, c)
     else:
       result = genCopy(c, dest.typ, dest, ri)
       result.add p(ri, c)
@@ -512,14 +576,15 @@ proc p(n: PNode; c: var Con): PNode =
       if it.kind == nkVarTuple and hasDestructor(ri.typ):
         let x = lowerTupleUnpacking(c.graph, it, c.owner)
         result.add p(x, c)
-      elif it.kind == nkIdentDefs and hasDestructor(it[0].typ) and not isUnpackedTuple(it[0].sym):
+      elif it.kind == nkIdentDefs and hasDestructor(it[0].typ):
         for j in 0..L-2:
           let v = it[j]
           doAssert v.kind == nkSym
           # move the variable declaration to the top of the frame:
           c.addTopVar v
           # make sure it's destroyed at the end of the proc:
-          c.destroys.add genDestroy(c, v.typ, v)
+          if not isUnpackedTuple(it[0].sym):
+            c.destroys.add genDestroy(c, v.typ, v)
           if ri.kind != nkEmpty:
             let r = moveOrCopy(v, ri, c)
             result.add r
@@ -566,12 +631,8 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
     echo "injecting into ", n
   var c: Con
   c.owner = owner
-  c.tmp = newSym(skTemp, getIdent(g.cache, ":d"), owner, n.info)
-  c.tmpObj = createObj(g, owner, n.info)
-  c.tmp.typ = c.tmpObj
   c.destroys = newNodeI(nkStmtList, n.info)
   c.topLevelVars = newNodeI(nkVarSection, n.info)
-  c.toDropBit = initTable[int, PSym]()
   c.graph = g
   c.emptyNode = newNodeI(nkEmpty, n.info)
   let cfg = constructCfg(owner, n)
@@ -586,10 +647,10 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
     let params = owner.typ.n
     for i in 1 ..< params.len:
       let param = params[i].sym
-      if param.typ.kind == tySink: registerDropBit(c, param)
+      if param.typ.kind == tySink: 
+        c.destroys.add genDestroy(c, param.typ.skipTypes({tyGenericInst, tyAlias, tySink}), params[i])
+
   let body = p(n, c)
-  if c.tmp.typ.n.len > 0:
-    c.addTopVar(newSymNode c.tmp)
   result = newNodeI(nkStmtList, n.info)
   if c.topLevelVars.len > 0:
     result.add c.topLevelVars
diff --git a/compiler/dfa.nim b/compiler/dfa.nim
index 415cc4ab3..cd32d95d5 100644
--- a/compiler/dfa.nim
+++ b/compiler/dfa.nim
@@ -272,7 +272,7 @@ proc genReturn(c: var Con; n: PNode) =
   c.code.add Instr(n: n, kind: goto, dest: high(int) - c.code.len)
 
 const
-  InterestingSyms = {skVar, skResult, skLet}
+  InterestingSyms = {skVar, skResult, skLet, skParam}
 
 proc genUse(c: var Con; n: PNode) =
   var n = n
diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim
index 09a1cd436..0f9220102 100644
--- a/compiler/evaltempl.nim
+++ b/compiler/evaltempl.nim
@@ -37,18 +37,21 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
   case templ.kind
   of nkSym:
     var s = templ.sym
-    if s.owner.id == c.owner.id:
+    if s.owner == nil or s.owner.id == c.owner.id:
       if s.kind == skParam and sfGenSym notin s.flags:
         handleParam actual.sons[s.position]
-      elif s.kind == skGenericParam or
-           s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam:
+      elif (s.owner != nil) and (s.kind == skGenericParam or
+           s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam):
         handleParam actual.sons[s.owner.typ.len + s.position - 1]
       else:
         internalAssert c.config, sfGenSym in s.flags or s.kind == skType
         var x = PSym(idTableGet(c.mapping, s))
         if x == nil:
           x = copySym(s)
-          x.owner = c.genSymOwner
+          # sem'check needs to set the owner properly later, see bug #9476
+          x.owner = nil # c.genSymOwner
+          #if x.kind == skParam and x.owner.kind == skModule:
+          #  internalAssert c.config, false
           idTablePut(c.mapping, s, x)
         result.add newSymNode(x, if c.instLines: actual.info else: templ.info)
     else:
@@ -173,6 +176,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
   initIdTable(ctx.mapping)
 
   let body = tmpl.getBody
+  #echo "instantion of ", renderTree(body, {renderIds})
   if isAtom(body):
     result = newNodeI(nkPar, body.info)
     evalTemplateAux(body, args, ctx, result)
@@ -189,5 +193,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
       evalTemplateAux(body.sons[i], args, ctx, result)
   result.flags.incl nfFromTemplate
   result = wrapInComesFrom(n.info, tmpl, result)
+  #if ctx.debugActive:
+  #  echo "instantion of ", renderTree(result, {renderIds})
   dec(conf.evalTemplateCounter)
 
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index 874cb4bd0..ddde1be31 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -407,11 +407,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
               obj.n[0].sym.id = -s.id
             else:
               addField(obj, s, c.graph.cache)
-      # but always return because the rest of the proc is only relevant when
-      # ow != owner:
-      return
     # direct or indirect dependency:
-    if (innerProc and s.typ.callConv == ccClosure) or interestingVar(s):
+    elif (innerProc and s.typ.callConv == ccClosure) or interestingVar(s):
       discard """
         proc outer() =
           var x: int
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index 2fb4e5241..db03ac2e0 100644
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -169,7 +169,7 @@ proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) =
             getSymRepr(c.config, s))
       inc missingImpls
     elif {sfUsed, sfExported} * s.flags == {}:
-      if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}:
+      if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam, skEnumField}:
         # XXX: implicit type params are currently skTypes
         # maybe they can be made skGenericParam as well.
         if s.typ != nil and tfImplicitTypeParam notin s.typ.flags and
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 924e53b66..8332af346 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -207,11 +207,12 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
     if result.kind notin {kind, skTemp}:
       localError(c.config, n.info, "cannot use symbol of kind '" &
                  $result.kind & "' as a '" & $kind & "'")
-    if sfGenSym in result.flags and result.kind notin {skTemplate, skMacro, skParam}:
-      # declarative context, so produce a fresh gensym:
-      result = copySym(result)
-      result.ast = n.sym.ast
-      put(c.p, n.sym, result)
+    when false:
+      if sfGenSym in result.flags and result.kind notin {skTemplate, skMacro, skParam}:
+        # declarative context, so produce a fresh gensym:
+        result = copySym(result)
+        result.ast = n.sym.ast
+        put(c.p, n.sym, result)
     # when there is a nested proc inside a template, semtmpl
     # will assign a wrong owner during the first pass over the
     # template; we must fix it here: see #909
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 08917cb29..ddec457a1 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1083,6 +1083,8 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
       # XXX see the hack in sigmatch.nim ...
       return s.typ.n
     elif sfGenSym in s.flags:
+      # the owner should have been set by now by addParamOrResult
+      internalAssert c.config, s.owner != nil
       if c.p.wasForwarded:
         # gensym'ed parameters that nevertheless have been forward declared
         # need a special fixup:
@@ -2289,6 +2291,8 @@ proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode =
     var labl = newSymG(skLabel, n.sons[0], c)
     if sfGenSym notin labl.flags:
       addDecl(c, labl)
+    elif labl.owner == nil:
+      labl.owner = c.p.owner
     n.sons[0] = newSymNode(labl, n.sons[0].info)
     suggestSym(c.config, n.sons[0].info, labl, c.graph.usageSym)
     styleCheckDef(c.config, labl)
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 5ec702257..df6298eb0 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -626,6 +626,14 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
         # It doesn't matter if the argument is const or not for mLengthArray.
         # This fixes bug #544.
         result = newIntNodeT(lengthOrd(g.config, n.sons[1].typ), n, g)
+      of mSizeOf:
+        let size = getSize(g.config, n[1].typ)
+        if size >= 0:
+          result = newIntNode(nkIntLit, size)
+          result.info = n.info
+          result.typ = getSysType(g, n.info, tyInt)
+        else:
+          result = nil
       of mAstToStr:
         result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, g)
       of mConStrStr:
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 17f61c7dd..09991048e 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -116,7 +116,7 @@ proc freshGenSyms(n: PNode, owner, orig: PSym, symMap: var TIdTable) =
     var x = PSym(idTableGet(symMap, s))
     if x != nil:
       n.sym = x
-    elif s.owner.kind == skPackage:
+    elif s.owner == nil or s.owner.kind == skPackage:
       #echo "copied this ", s.name.s
       x = copySym(s)
       x.owner = owner
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index df2c084a1..7e61854b8 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -321,8 +321,6 @@ proc semOf(c: PContext, n: PNode): PNode =
 proc magicsAfterOverloadResolution(c: PContext, n: PNode,
                                    flags: TExprFlags): PNode =
   ## This is the preferred code point to implement magics.
-  ## This function basically works like a macro, with the difference
-  ## that it is implemented in the compiler and not on the nimvm.
   ## ``c`` the current module, a symbol table to a very good approximation
   ## ``n`` the ast like it would be passed to a real macro
   ## ``flags`` Some flags for more contextual information on how the
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 48aa75528..04fe91cfb 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -497,8 +497,10 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
       var v = semIdentDef(c, a.sons[j], symkind)
       styleCheckDef(c.config, v)
       onDef(a[j].info, v)
-      if sfGenSym notin v.flags and not isDiscardUnderscore(v):
-        addInterfaceDecl(c, v)
+      if sfGenSym notin v.flags:
+        if not isDiscardUnderscore(v): addInterfaceDecl(c, v)
+      else:
+        if v.owner == nil: v.owner = c.p.owner
       when oKeepVariableNames:
         if c.inUnrolledContext > 0: v.flags.incl(sfShadowed)
         else:
@@ -573,6 +575,7 @@ proc semConst(c: PContext, n: PNode): PNode =
     setVarType(c, v, typ)
     v.ast = def               # no need to copy
     if sfGenSym notin v.flags: addInterfaceDecl(c, v)
+    elif v.owner == nil: v.owner = getCurrOwner(c)
     var b = newNodeI(nkConstDef, a.info)
     if importantComments(c.config): b.comment = a.comment
     addSon(b, newSymNode(v))
@@ -616,6 +619,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
       v.typ = iterBase
       n.sons[0] = newSymNode(v)
       if sfGenSym notin v.flags: addForVarDecl(c, v)
+      elif v.owner == nil: v.owner = getCurrOwner(c)
     else:
       localError(c.config, n.info, errWrongNumberOfVariables)
   elif length-2 != sonsLen(iter):
@@ -626,8 +630,9 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
       if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal)
       v.typ = iter.sons[i]
       n.sons[i] = newSymNode(v)
-      if sfGenSym notin v.flags and not isDiscardUnderscore(v):
-        addForVarDecl(c, v)
+      if sfGenSym notin v.flags:
+        if not isDiscardUnderscore(v): addForVarDecl(c, v)
+      elif v.owner == nil: v.owner = getCurrOwner(c)
   inc(c.p.nestedLoopCounter)
   openScope(c)
   n.sons[length-1] = semExprBranch(c, n.sons[length-1], flags)
@@ -922,6 +927,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
             s = typsym
       # add it here, so that recursive types are possible:
       if sfGenSym notin s.flags: addInterfaceDecl(c, s)
+      elif s.owner == nil: s.owner = getCurrOwner(c)
 
     if name.kind == nkPragmaExpr:
       a.sons[0].sons[0] = newSymNode(s)
@@ -1620,7 +1626,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     else:
       s.typ.callConv = lastOptionEntry(c).defaultCC
     # add it here, so that recursive procs are possible:
-    if sfGenSym in s.flags: discard
+    if sfGenSym in s.flags:
+      if s.owner == nil: s.owner = getCurrOwner(c)
     elif kind in OverloadableSyms:
       if not typeIsDetermined:
         addInterfaceOverloadableSymAt(c, oldScope, s)
@@ -1836,17 +1843,33 @@ proc semMacroDef(c: PContext, n: PNode): PNode =
   if n.sons[bodyPos].kind == nkEmpty:
     localError(c.config, n.info, errImplOfXexpected % s.name.s)
 
+proc incMod(c: PContext, n: PNode, it: PNode, includeStmtResult: PNode) =
+  var f = checkModuleName(c.config, it)
+  if f != InvalidFileIDX:
+    if containsOrIncl(c.includedFiles, f.int):
+      localError(c.config, n.info, errRecursiveDependencyX % toFilename(c.config, f))
+    else:
+      addSon(includeStmtResult, semStmt(c, c.graph.includeFileCallback(c.graph, c.module, f), {}))
+      excl(c.includedFiles, f.int)
+
 proc evalInclude(c: PContext, n: PNode): PNode =
   result = newNodeI(nkStmtList, n.info)
   addSon(result, n)
   for i in countup(0, sonsLen(n) - 1):
-    var f = checkModuleName(c.config, n.sons[i])
-    if f != InvalidFileIDX:
-      if containsOrIncl(c.includedFiles, f.int):
-        localError(c.config, n.info, errRecursiveDependencyX % toFilename(c.config, f))
-      else:
-        addSon(result, semStmt(c, c.graph.includeFileCallback(c.graph, c.module, f), {}))
-        excl(c.includedFiles, f.int)
+    var imp: PNode
+    let it = n.sons[i]
+    if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket:
+      let sep = it[0]
+      let dir = it[1]
+      imp = newNodeI(nkInfix, it.info)
+      imp.add sep
+      imp.add dir
+      imp.add sep # dummy entry, replaced in the loop
+      for x in it[2]:
+        imp.sons[2] = x
+        incMod(c, n, imp, result)
+    else:
+      incMod(c, n, it, result)
 
 proc setLine(n: PNode, info: TLineInfo) =
   for i in 0 ..< safeLen(n): setLine(n.sons[i], info)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index a011a8fc8..f4ff97ba4 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -90,6 +90,8 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
         if sonsLen(v) == 2:
           strVal = v.sons[1] # second tuple part is the string value
           if skipTypes(strVal.typ, abstractInst).kind in {tyString, tyCString}:
+            if not isOrdinalType(v.sons[0].typ):
+              localError(c.config, v.sons[0].info, errOrdinalTypeExpected)
             x = getOrdValue(v.sons[0]) # first tuple part is the ordinal
           else:
             localError(c.config, strVal.info, errStringLiteralExpected)
@@ -99,6 +101,8 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
         strVal = v
         x = counter
       else:
+        if not isOrdinalType(v.typ):
+          localError(c.config, v.info, errOrdinalTypeExpected)
         x = getOrdValue(v)
       if i != 1:
         if x != counter: incl(result.flags, tfEnumHasHoles)
@@ -821,7 +825,11 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
       a.typ = nn.typ
       addDecl(c, a)
   else:
-    if sfGenSym notin param.flags: addDecl(c, param)
+    if sfGenSym in param.flags:
+      # bug #XXX, fix the gensym'ed parameters owner:
+      if param.owner == nil:
+        param.owner = getCurrOwner(c)
+    else: addDecl(c, param)
 
 template shouldHaveMeta(t) =
   internalAssert c.config, tfHasMeta in t.flags
diff --git a/koch.nim b/koch.nim
index 9a8d38a79..bd10224b6 100644
--- a/koch.nim
+++ b/koch.nim
@@ -79,6 +79,7 @@ template withDir(dir, body) =
   finally:
     setCurrentdir(old)
 
+let origDir = getCurrentDir()
 setCurrentDir(getAppDir())
 
 proc tryExec(cmd: string): bool =
@@ -415,6 +416,7 @@ proc temp(args: string) =
   let nimexec = findNim()
   exec(nimexec & " c -d:debug --debugger:native " & bootArgs & " " & (d / "compiler" / "nim"), 125)
   copyExe(output, finalDest)
+  setCurrentDir(origDir)
   if programArgs.len > 0: exec(finalDest & " " & programArgs)
 
 proc xtemp(cmd: string) =
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index aef4f1ce6..36319a317 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -1513,8 +1513,217 @@ proc poll*(timeout = 500) =
   ## `epoll`:idx: or `kqueue`:idx: primitive only once.
   discard runOnce(timeout)
 
-# Common procedures between current and upcoming asyncdispatch
-include includes/asynccommon
+template createAsyncNativeSocketImpl(domain, sockType, protocol) =
+  let handle = newNativeSocket(domain, sockType, protocol)
+  if handle == osInvalidSocket:
+    return osInvalidSocket.AsyncFD
+  handle.setBlocking(false)
+  when defined(macosx) and not defined(nimdoc):
+    handle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
+  result = handle.AsyncFD
+  register(result)
+
+proc createAsyncNativeSocket*(domain: cint, sockType: cint,
+                           protocol: cint): AsyncFD =
+  createAsyncNativeSocketImpl(domain, sockType, protocol)
+
+proc createAsyncNativeSocket*(domain: Domain = Domain.AF_INET,
+                           sockType: SockType = SOCK_STREAM,
+                           protocol: Protocol = IPPROTO_TCP): AsyncFD =
+  createAsyncNativeSocketImpl(domain, sockType, protocol)
+
+proc newAsyncNativeSocket*(domain: cint, sockType: cint,
+                           protocol: cint): AsyncFD {.deprecated: "use createAsyncNativeSocket instead".} =
+  createAsyncNativeSocketImpl(domain, sockType, protocol)
+
+proc newAsyncNativeSocket*(domain: Domain = Domain.AF_INET,
+                           sockType: SockType = SOCK_STREAM,
+                           protocol: Protocol = IPPROTO_TCP): AsyncFD
+                           {.deprecated: "use createAsyncNativeSocket instead".} =
+  createAsyncNativeSocketImpl(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 = uint16(toInt(domain))
+      doBind(saddr)
+    else:
+      var saddr: Sockaddr_in
+      saddr.sin_family = uint16(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)
 
 proc sleepAsync*(ms: int | float): Future[void] =
   ## Suspends the execution of the current async procedure for the next
diff --git a/lib/pure/includes/asynccommon.nim b/lib/pure/includes/asynccommon.nim
deleted file mode 100644
index 13887acc9..000000000
--- a/lib/pure/includes/asynccommon.nim
+++ /dev/null
@@ -1,211 +0,0 @@
-template createAsyncNativeSocketImpl(domain, sockType, protocol) =
-  let handle = newNativeSocket(domain, sockType, protocol)
-  if handle == osInvalidSocket:
-    return osInvalidSocket.AsyncFD
-  handle.setBlocking(false)
-  when defined(macosx) and not defined(nimdoc):
-    handle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
-  result = handle.AsyncFD
-  register(result)
-
-proc createAsyncNativeSocket*(domain: cint, sockType: cint,
-                           protocol: cint): AsyncFD =
-  createAsyncNativeSocketImpl(domain, sockType, protocol)
-
-proc createAsyncNativeSocket*(domain: Domain = Domain.AF_INET,
-                           sockType: SockType = SOCK_STREAM,
-                           protocol: Protocol = IPPROTO_TCP): AsyncFD =
-  createAsyncNativeSocketImpl(domain, sockType, protocol)
-
-proc newAsyncNativeSocket*(domain: cint, sockType: cint,
-                           protocol: cint): AsyncFD {.deprecated: "use createAsyncNativeSocket instead".} =
-  createAsyncNativeSocketImpl(domain, sockType, protocol)
-
-proc newAsyncNativeSocket*(domain: Domain = Domain.AF_INET,
-                           sockType: SockType = SOCK_STREAM,
-                           protocol: Protocol = IPPROTO_TCP): AsyncFD
-                           {.deprecated: "use createAsyncNativeSocket instead".} =
-  createAsyncNativeSocketImpl(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 = uint16(toInt(domain))
-      doBind(saddr)
-    else:
-      var saddr: Sockaddr_in
-      saddr.sin_family = uint16(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/tests/destructor/tmatrix.nim b/tests/destructor/tmatrix.nim
index a16bfa37b..b89b41a4c 100644
--- a/tests/destructor/tmatrix.nim
+++ b/tests/destructor/tmatrix.nim
@@ -52,6 +52,8 @@ proc matrix*(m, n: int, s: float): Matrix =
   for i in 0 ..< m * n:
     result.data[i] = s
 
+proc len(m: Matrix): int = m.n * m.m
+
 proc `[]`*(m: Matrix, i, j: int): float {.inline.} =
   ## Get a single element.
   m.data[i * m.n + j]
@@ -67,24 +69,26 @@ proc `[]=`*(m: var Matrix, i, j: int, s: float) =
 proc `-`*(m: sink Matrix): Matrix =
   ## Unary minus
   result = m
-  for i in 0 ..< m.m:
-    for j in 0 ..< m.n:
-      result[i, j] = -m[i, j]
+  for i in 0 ..< result.m:
+    for j in 0 ..< result.n:
+      result[i, j] = -result[i, j]
 
 proc `+`*(a: sink Matrix; b: Matrix): Matrix =
   ## ``C = A + B``
-  assert(b.m == a.m and b.n == a.n, "Matrix dimensions must agree.")
+  doAssert(b.m == a.m and b.n == a.n, "Matrix dimensions must agree.")
+  doAssert(a.len == b.len) # non destructive use before sink is ok
   result = a
-  for i in 0 ..< a.m:
-    for j in 0 ..< a.n:
-      result[i, j] = a[i, j] + b[i, j]
+  for i in 0 ..< result.m:
+    for j in 0 ..< result.n:
+      result[i, j] = result[i, j] + b[i, j]
 
 proc `-`*(a: sink Matrix; b: Matrix): Matrix =
   ## ``C = A - B``
   assert(b.m == a.m and b.n == a.n, "Matrix dimensions must agree.")
+  doAssert(a.len == b.len) # non destructive use before sink is ok
   result = a
-  for i in 0 ..< a.m:
-     for j in 0 ..< a.n:
+  for i in 0 ..< result.m:
+     for j in 0 ..< result.n:
         result[i, j] = a[i, j] - b[i, j]
 
 proc info =
diff --git a/tests/destructor/tmove_objconstr.nim b/tests/destructor/tmove_objconstr.nim
index 26cc682b5..51aba1592 100644
--- a/tests/destructor/tmove_objconstr.nim
+++ b/tests/destructor/tmove_objconstr.nim
@@ -109,7 +109,19 @@ proc myfunc(x, y: int): (MySeqNonCopyable, MySeqNonCopyable) =
 
 proc myfunc2(x, y: int): tuple[a: MySeqNonCopyable, b:int, c:MySeqNonCopyable] =
   var cc = newMySeq(y, 5.0)
-  (a: newMySeq(x, 1.0), b:0, c: cc)
+  (a: case x:
+    of 1: 
+      let (z1, z2) = myfunc(x,y)
+      z2
+    elif x > 5: raise newException(ValueError, "new error")
+    else: newMySeq(x, 1.0), 
+   b: 0, 
+   c: block:
+        var tmp = if y > 0: move(cc) else: newMySeq(1, 3.0)
+        tmp[0] = 5
+        tmp 
+  )
+   
 
 let (seq1, seq2) = myfunc(2, 3)
 doAssert seq1.len == 2
@@ -122,4 +134,35 @@ doAssert seq3.len == 2
 doAssert seq3[0] == 1.0
 
 var seq4, seq5: MySeqNonCopyable
-(seq4, i, seq5) = myfunc2(2, 3)
\ No newline at end of file
+(seq4, i, seq5) = myfunc2(2, 3)
+
+seq4 = block:
+  var tmp = newMySeq(4, 1.0)
+  tmp[0] = 3.0
+  tmp
+
+doAssert seq4[0] == 3.0 
+
+import macros
+
+seq4 = 
+  if i > 0: newMySeq(2, 5.0) 
+  elif i < -100: raise newException(ValueError, "Parse Error")
+  else: newMySeq(2, 3.0)
+
+seq4 = 
+  case (char) i:
+    of 'A', {'W'..'Z'}: newMySeq(2, 5.0) 
+    of 'B': quit(-1)
+    else: 
+      let (x1, x2, x3) = myfunc2(2, 3)
+      x3
+
+
+#------------------------------------------------------------
+#-- Move into array constructor
+#------------------------------------------------------------
+
+var ii = 1
+let arr2 = [newMySeq(2, 5.0), if i > 1: newMySeq(3, 1.0) else: newMySeq(0, 0.0)]
+var seqOfSeq2 = @[newMySeq(2, 5.0), newMySeq(3, 1.0)]
diff --git a/tests/errmsgs/t9908_01.nim b/tests/errmsgs/t9908_01.nim
new file mode 100644
index 000000000..b9d37b67b
--- /dev/null
+++ b/tests/errmsgs/t9908_01.nim
@@ -0,0 +1,10 @@
+discard """
+errormsg: "ordinal type expected"
+line: 10
+"""
+
+# https://github.com/nim-lang/Nim/issues/9908
+
+type
+  X = enum
+    a = ("a", "b")
diff --git a/tests/errmsgs/t9908_02.nim b/tests/errmsgs/t9908_02.nim
new file mode 100644
index 000000000..7ff3d1ff7
--- /dev/null
+++ b/tests/errmsgs/t9908_02.nim
@@ -0,0 +1,10 @@
+discard """
+errormsg: "ordinal type expected"
+line: 10
+"""
+
+# https://github.com/nim-lang/Nim/pull/9909#issuecomment-445519287
+
+type
+  E = enum
+    myVal = 80.9
diff --git a/tests/misc/tsizeof2.nim b/tests/misc/tsizeof2.nim
index 4252142d7..130f28e21 100644
--- a/tests/misc/tsizeof2.nim
+++ b/tests/misc/tsizeof2.nim
@@ -13,3 +13,5 @@ echo i
 # bug #9868
 proc foo(a: SomeInteger): array[sizeof(a), byte] =
   discard
+
+discard foo(1)
diff --git a/tests/modules/m9627/a.nim b/tests/modules/m9627/a.nim
new file mode 100644
index 000000000..0dd32430e
--- /dev/null
+++ b/tests/modules/m9627/a.nim
@@ -0,0 +1 @@
+var a = 10
diff --git a/tests/modules/m9627/b.nim b/tests/modules/m9627/b.nim
new file mode 100644
index 000000000..2806a78ed
--- /dev/null
+++ b/tests/modules/m9627/b.nim
@@ -0,0 +1 @@
+var b = 9
diff --git a/tests/modules/t9627.nim b/tests/modules/t9627.nim
new file mode 100644
index 000000000..daba46374
--- /dev/null
+++ b/tests/modules/t9627.nim
@@ -0,0 +1,7 @@
+discard """
+  output: "109"
+"""
+
+include m9627 / [a, b]
+
+echo a, b
diff --git a/tests/pragmas/tused.nim b/tests/pragmas/tused.nim
index 83c62b7bb..dce854146 100644
--- a/tests/pragmas/tused.nim
+++ b/tests/pragmas/tused.nim
@@ -31,5 +31,11 @@ block:
   implementArithOpsNew(int)
   echoAdd 3, 5
 
+# issue #9896
+type
+  MyEnum {.used.} = enum
+    Val1, Val2, Val3
+
+
 static:
   echo "compile end"
diff --git a/tests/template/tparams_gensymed.nim b/tests/template/tparams_gensymed.nim
index da86d63dc..91fa26596 100644
--- a/tests/template/tparams_gensymed.nim
+++ b/tests/template/tparams_gensymed.nim
@@ -70,3 +70,43 @@ proc genericProc(x: any) =
 
 concreteProc(7) # This works
 genericProc(7)  # This doesn't compile
+
+import tables
+
+# bug #9476
+proc getTypeInfo*(T: typedesc): pointer =
+  var dummy: T
+  getTypeInfo(dummy)
+
+
+macro implementUnary(op: untyped): untyped =
+  result = newStmtList()
+
+  template defineTable(tableSymbol) =
+    var tableSymbol = initTable[pointer, pointer]()
+  let tableSymbol = genSym(nskVar, "registeredProcs")
+  result.add(getAst(defineTable(tableSymbol)))
+
+  template defineRegisterInstantiation(tableSym, regTemplSym, instSym, op) =
+    template regTemplSym*(T: typedesc) =
+      let ti = getTypeInfo(T)
+
+      proc instSym(xOrig: int): int {.gensym, cdecl.} =
+        let x {.inject.} = xOrig
+        op
+
+      tableSym[ti] = cast[pointer](instSym)
+
+  let regTemplSymbol = ident("registerInstantiation")
+  let instSymbol = ident("instantiation")
+  result.add(getAst(defineRegisterInstantiation(
+    tableSymbol, regTemplSymbol, instSymbol, op
+  )))
+
+  echo result.repr
+
+
+implementUnary(): x*x
+
+registerInstantiation(int)
+registerInstantiation(float)