summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/aliases.nim182
-rwxr-xr-xcompiler/ast.nim33
-rwxr-xr-xcompiler/astalgo.nim24
-rw-r--r--compiler/ccgcalls.nim92
-rwxr-xr-xcompiler/ccgexprs.nim12
-rwxr-xr-xcompiler/ccgstmts.nim26
-rwxr-xr-xcompiler/cgen.nim29
-rwxr-xr-xcompiler/ecmasgen.nim13
-rwxr-xr-xcompiler/evals.nim9
-rwxr-xr-xcompiler/pragmas.nim2
-rwxr-xr-xcompiler/sem.nim2
-rwxr-xr-xcompiler/semexprs.nim40
-rwxr-xr-xcompiler/semfold.nim2
-rw-r--r--compiler/semmagic.nim38
-rwxr-xr-xcompiler/types.nim1
-rwxr-xr-xdoc/manual.txt6
-rw-r--r--lib/pure/actors.nim43
-rwxr-xr-xlib/system.nim14
-rwxr-xr-xlib/system/channels.nim5
-rwxr-xr-xtests/run/tpegs.nim74
-rw-r--r--tests/run/tuserassert.nim1
-rw-r--r--tests/specials.nim1
-rw-r--r--tests/threads/trecursive_actor.nim19
-rwxr-xr-xtodo.txt8
-rwxr-xr-xweb/news.txt11
25 files changed, 486 insertions, 201 deletions
diff --git a/compiler/aliases.nim b/compiler/aliases.nim
new file mode 100644
index 000000000..aa579feee
--- /dev/null
+++ b/compiler/aliases.nim
@@ -0,0 +1,182 @@
+#
+#
+#           The Nimrod Compiler
+#        (c) Copyright 2011 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Simple alias analysis for the HLO and the code generators.
+
+import
+  ast, astalgo, types, trees, intsets, msgs
+  
+type
+  TAnalysisResult* = enum
+    arNo, arMaybe, arYes
+
+proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult
+
+proc isPartOfAux(n: PNode, b: PType, marker: var TIntSet): TAnalysisResult =
+  result = arNo
+  case n.kind
+  of nkRecList: 
+    for i in countup(0, sonsLen(n) - 1): 
+      result = isPartOfAux(n.sons[i], b, marker)
+      if result == arYes: return
+  of nkRecCase:
+    assert(n.sons[0].kind == nkSym)
+    result = isPartOfAux(n.sons[0], b, marker)
+    if result == arYes: return
+    for i in countup(1, sonsLen(n) - 1): 
+      case n.sons[i].kind
+      of nkOfBranch, nkElse: 
+        result = isPartOfAux(lastSon(n.sons[i]), b, marker)
+        if result == arYes: return
+      else: internalError("isPartOfAux(record case branch)")
+  of nkSym:
+    result = isPartOfAux(n.sym.typ, b, marker)
+  else: internalError(n.info, "isPartOfAux()")
+  
+proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult = 
+  result = arNo
+  if a == nil or b == nil: return 
+  if ContainsOrIncl(marker, a.id): return 
+  if compareTypes(a, b, dcEqIgnoreDistinct): return arYes
+  case a.kind
+  of tyObject: 
+    result = isPartOfAux(a.sons[0], b, marker)
+    if result == arNo: result = isPartOfAux(a.n, b, marker)
+  of tyGenericInst, tyDistinct:
+    result = isPartOfAux(lastSon(a), b, marker)
+  of tyArray, tyArrayConstr, tySet, tyTuple: 
+    for i in countup(0, sonsLen(a) - 1): 
+      result = isPartOfAux(a.sons[i], b, marker)
+      if result == arYes: return 
+  else: nil
+
+proc isPartOf(a, b: PType): TAnalysisResult = 
+  ## checks iff 'a' can be part of 'b'. Iterates over VALUE types!
+  var marker = InitIntSet()
+  # watch out: parameters reversed because I'm too lazy to change the code...
+  result = isPartOfAux(b, a, marker)
+
+proc isPartOf*(a, b: PNode): TAnalysisResult =
+  ## checks if location `a` can be part of location `b`. We treat seqs and
+  ## strings as pointers because the code gen often just passes them as such.
+  ##
+  ## Note: `a` can only be part of `b`, if `a`'s type can be part of `b`'s
+  ## type. Since however type analysis is more expensive, we perform it only
+  ## if necessary.
+  ##
+  ## cases: 
+  ##
+  ## YES-cases:
+  ##  x    <| x   # for general trees
+  ##  x[]  <| x
+  ##  x[i] <| x
+  ##  x.f  <| x
+  ##  
+  ## NO-cases:
+  ## x           !<| y    # depending on type and symbol kind
+  ## x[constA]   !<| x[constB]
+  ## x.f         !<| x.g
+  ## x.f         !<| y.f  iff x !<= y
+  ##
+  ## MAYBE-cases:
+  ##
+  ##  x[] ?<| y[]   iff compatible type
+  ##
+  ## 
+  ##  x[]  ?<| y  depending on type
+  ##  
+  if a.kind == b.kind:
+    case a.kind
+    of nkSym:
+      const varKinds = {skVar, skTemp, skProc}
+      # same symbol: aliasing:
+      if a.sym.id == b.sym.id: result = arYes
+      elif a.sym.kind in varKinds or b.sym.kind in varKinds: 
+        # actually, a param could alias a var but we know that cannot happen
+        # here. XXX make this more generic
+        result = arNo
+      else:
+        # use expensive type check:
+        if isPartOf(a.sym.typ, b.sym.typ) != arNo:
+          result = arMaybe
+    of nkBracketExpr:
+      result = isPartOf(a[0], b[0])
+      if len(a) >= 2 and len(b) >= 2:
+        # array accesses:
+        if result == arYes and isDeepConstExpr(a[1]) and isDeepConstExpr(b[1]):
+          # we know it's the same array and we have 2 constant indexes; 
+          # if they are 
+          var x = if a[1].kind == nkHiddenStdConv: a[1][1] else: a[1]
+          var y = if b[1].kind == nkHiddenStdConv: b[1][1] else: b[1]
+          
+          if SameValue(x, y): result = arYes
+          else: result = arNo
+        # else: maybe and no are accurate
+      else:
+        # pointer derefs:
+        if result != arYes:
+          if isPartOf(a.typ, b.typ) != arNo: result = arMaybe
+      
+    of nkDotExpr:
+      result = isPartOf(a[0], b[0])
+      if result != arNo:
+        # if the fields are different, it's not the same location
+        if a[1].sym.id != b[1].sym.id:
+          result = arNo
+
+    of nkHiddenDeref, nkDerefExpr:
+      result = isPartOf(a[0], b[0])
+      # weaken because of indirection:
+      if result != arYes:
+        if isPartOf(a.typ, b.typ) != arNo: result = arMaybe
+      
+    of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+      result = isPartOf(a[1], b[1])
+    of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
+      result = isPartOf(a[0], b[0])
+    else: nil
+    # Calls return a new location, so a default of ``arNo`` is fine.
+  else:
+    # go down recursively; this is quite demanding:
+    const 
+      Ix0Kinds = {nkDotExpr, nkBracketExpr, nkObjUpConv, nkObjDownConv,
+                  nkCheckedFieldExpr}
+      Ix1Kinds = {nkHiddenStdConv, nkHiddenSubConv, nkConv}
+      DerefKinds = {nkHiddenDeref, nkDerefExpr}
+    case b.kind
+    of Ix0Kinds:
+      # a* !<| b.f  iff  a* !<| b
+      result = isPartOf(a, b[0])
+    
+    of DerefKinds:
+      # a* !<| b[] iff 
+      if isPartOf(a.typ, b.typ) != arNo:
+        result = isPartOf(a, b[0])
+        if result == arNo: result = arMaybe
+    
+    of Ix1Kinds:
+      # a* !<| T(b)  iff a* !<| b
+      result = isPartOf(a, b[1])
+    
+    of nkSym:
+      # b is an atom, so we have to check a:
+      case a.kind
+      of Ix0Kinds:
+        # a.f !<| b*  iff  a.f !<| b*
+        result = isPartOf(a[0], b)
+      of Ix1Kinds:
+        result = isPartOf(a[1], b)
+      
+      of DerefKinds:
+        if isPartOf(a.typ, b.typ) != arNo:
+          result = isPartOf(a[0], b)
+          if result == arNo: result = arMaybe
+      else: nil
+    else: nil
+
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 6ac7dc0de..8d1aeeb6a 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -371,7 +371,7 @@ type
     mFields, mFieldPairs,
     mAppendStrCh, mAppendStrStr, mAppendSeqElem, 
     mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, 
-    mAssert, mAstToStr, mRand,
+    mIsPartOf, mAstToStr, mRand, 
     mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, 
     mNewString, mNewStringOfCap,
     mReset,
@@ -669,36 +669,7 @@ const                         # for all kind of hash tables:
   GrowthFactor* = 2           # must be power of 2, > 0
   StartSize* = 8              # must be power of 2, > 0
 
-proc SameValue*(a, b: PNode): bool
-  # a, b are literals
-proc leValue*(a, b: PNode): bool
-  # a <= b? a, b are literals
-proc ValueToString*(a: PNode): string
- 
-proc leValue(a, b: PNode): bool = 
-  # a <= b?
-  result = false
-  case a.kind
-  of nkCharLit..nkInt64Lit: 
-    if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal <= b.intVal
-  of nkFloatLit..nkFloat64Lit: 
-    if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal
-  of nkStrLit..nkTripleStrLit: 
-    if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal <= b.strVal
-  else: InternalError(a.info, "leValue")
-  
-proc SameValue(a, b: PNode): bool = 
-  result = false
-  case a.kind
-  of nkCharLit..nkInt64Lit: 
-    if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal == b.intVal
-  of nkFloatLit..nkFloat64Lit: 
-    if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal
-  of nkStrLit..nkTripleStrLit: 
-    if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal == b.strVal
-  else: InternalError(a.info, "SameValue")
-  
-proc ValueToString(a: PNode): string = 
+proc ValueToString*(a: PNode): string = 
   case a.kind
   of nkCharLit..nkInt64Lit: result = $(a.intVal)
   of nkFloatLit, nkFloat32Lit, nkFloat64Lit: result = $(a.floatVal)
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index 472a8d803..94046a723 100755
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -146,6 +146,30 @@ proc IITablePut*(t: var TIITable, key, val: int)
 
 # implementation
 
+proc SameValue*(a, b: PNode): bool = 
+  result = false
+  case a.kind
+  of nkCharLit..nkInt64Lit: 
+    if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal == b.intVal
+  of nkFloatLit..nkFloat64Lit: 
+    if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal
+  of nkStrLit..nkTripleStrLit: 
+    if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal == b.strVal
+  else:
+    InternalError(a.info, "SameValue")
+
+proc leValue*(a, b: PNode): bool = 
+  # a <= b?
+  result = false
+  case a.kind
+  of nkCharLit..nkInt64Lit: 
+    if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal <= b.intVal
+  of nkFloatLit..nkFloat64Lit: 
+    if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal
+  of nkStrLit..nkTripleStrLit: 
+    if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal <= b.strVal
+  else: InternalError(a.info, "leValue")
+
 proc lookupInRecord(n: PNode, field: PIdent): PSym = 
   result = nil
   case n.kind
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 1c57479ae..570c931fb 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -10,16 +10,30 @@
 type
   TAfterCallActions = tuple[p: BProc, actions: PRope]
 
-proc fixupCall(p: BProc, t: PNode, d: var TLoc, pl: PRope) =
+proc leftAppearsOnRightSide(le, ri: PNode): bool =
+  if le != nil:
+    for i in 1 .. <ri.len:
+      if le.isPartOf(ri[i]) != arNo: return true
+
+proc hasNoInit(call: PNode): bool {.inline.} =
+  result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags
+
+proc resetLoc(p: BProc, d: var TLoc) =
+  zeroVar(p, d, containsGarbageCollectedRef(d.t))
+
+proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl: PRope) =
   var pl = pl
-  var typ = t.sons[0].typ # getUniqueType() is too expensive here!
+  var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
   if typ.sons[0] != nil:
     if isInvalidReturnType(typ.sons[0]):
-      if sonsLen(t) > 1: app(pl, ", ")
-      # beware of 'result = p(result)'. We always allocate a temporary:
-      if d.k in {locTemp, locNone}:
-        # We already got a temp. Great, special case it:
+      if sonsLen(ri) > 1: app(pl, ", ")
+      # beware of 'result = p(result)'. We may need to allocate a temporary:
+      if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
+        # Great, we can use 'd':
         if d.k == locNone: getTemp(p, typ.sons[0], d)
+        elif d.k notin {locExpr, locTemp} and not hasNoInit(ri):
+          # reset before pass as 'result' var:
+          resetLoc(p, d)
         app(pl, addrLoc(d))
         app(pl, ")")
         app(p.s[cpsStmts], pl)
@@ -117,40 +131,40 @@ proc genArgNoParam(aca: var TAfterCallActions, n: PNode): PRope =
     initLocExpr(aca.p, n, a)
     result = rdLoc(a)
 
-proc genCall(p: BProc, t: PNode, d: var TLoc) =
+proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
   var op: TLoc
   var aca: TAfterCallActions
   aca.p = p
   # this is a hotspot in the compiler
-  initLocExpr(p, t.sons[0], op)
+  initLocExpr(p, ri.sons[0], op)
   var pl = con(op.r, "(")
-  var typ = t.sons[0].typ # getUniqueType() is too expensive here!
+  var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
   assert(typ.kind == tyProc)
-  var length = sonsLen(t)
+  var length = sonsLen(ri)
   for i in countup(1, length - 1):
     assert(sonsLen(typ) == sonsLen(typ.n))
     if i < sonsLen(typ):
       assert(typ.n.sons[i].kind == nkSym)
-      app(pl, genArg(aca, t.sons[i], typ.n.sons[i].sym))
+      app(pl, genArg(aca, ri.sons[i], typ.n.sons[i].sym))
     else:
-      app(pl, genArgNoParam(aca, t.sons[i]))
+      app(pl, genArgNoParam(aca, ri.sons[i]))
     if i < length - 1: app(pl, ", ")
-  fixupCall(p, t, d, pl)
+  fixupCall(p, le, ri, d, pl)
   emitAfterCallActions(aca)
 
-proc genInfixCall(p: BProc, t: PNode, d: var TLoc) =
+proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
   var op, a: TLoc
   var aca: TAfterCallActions
   aca.p = p
-  initLocExpr(p, t.sons[0], op)
+  initLocExpr(p, ri.sons[0], op)
   var pl: PRope = nil
-  var typ = t.sons[0].typ # getUniqueType() is too expensive here!
+  var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
   assert(typ.kind == tyProc)
-  var length = sonsLen(t)
+  var length = sonsLen(ri)
   assert(sonsLen(typ) == sonsLen(typ.n))
   
   var param = typ.n.sons[1].sym
-  app(pl, genArg(aca, t.sons[1], param))
+  app(pl, genArg(aca, ri.sons[1], param))
   
   if skipTypes(param.typ, {tyGenericInst}).kind == tyPtr: app(pl, "->")
   else: app(pl, ".")
@@ -160,45 +174,45 @@ proc genInfixCall(p: BProc, t: PNode, d: var TLoc) =
     assert(sonsLen(typ) == sonsLen(typ.n))
     if i < sonsLen(typ):
       assert(typ.n.sons[i].kind == nkSym)
-      app(pl, genArg(aca, t.sons[i], typ.n.sons[i].sym))
+      app(pl, genArg(aca, ri.sons[i], typ.n.sons[i].sym))
     else:
-      app(pl, genArgNoParam(aca, t.sons[i]))
+      app(pl, genArgNoParam(aca, ri.sons[i]))
     if i < length - 1: app(pl, ", ")
-  fixupCall(p, t, d, pl)
+  fixupCall(p, le, ri, d, pl)
   emitAfterCallActions(aca)
 
-proc genNamedParamCall(p: BProc, t: PNode, d: var TLoc) =
+proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
   # generates a crappy ObjC call
   var op, a: TLoc
   var aca: TAfterCallActions
   aca.p = p
-  initLocExpr(p, t.sons[0], op)
+  initLocExpr(p, ri.sons[0], op)
   var pl = toRope"["
-  var typ = t.sons[0].typ # getUniqueType() is too expensive here!
+  var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
   assert(typ.kind == tyProc)
-  var length = sonsLen(t)
+  var length = sonsLen(ri)
   assert(sonsLen(typ) == sonsLen(typ.n))
   
   if length > 1:
-    app(pl, genArg(aca, t.sons[1], typ.n.sons[1].sym))
+    app(pl, genArg(aca, ri.sons[1], typ.n.sons[1].sym))
     app(pl, " ")
   app(pl, op.r)
   if length > 2:
     app(pl, ": ")
-    app(pl, genArg(aca, t.sons[2], typ.n.sons[2].sym))
+    app(pl, genArg(aca, ri.sons[2], typ.n.sons[2].sym))
   for i in countup(3, length-1):
     assert(sonsLen(typ) == sonsLen(typ.n))
     if i >= sonsLen(typ):
-      InternalError(t.info, "varargs for objective C method?")
+      InternalError(ri.info, "varargs for objective C method?")
     assert(typ.n.sons[i].kind == nkSym)
     var param = typ.n.sons[i].sym
     app(pl, " ")
     app(pl, param.name.s)
     app(pl, ": ")
-    app(pl, genArg(aca, t.sons[i], param))
+    app(pl, genArg(aca, ri.sons[i], param))
   if typ.sons[0] != nil:
     if isInvalidReturnType(typ.sons[0]):
-      if sonsLen(t) > 1: app(pl, " ")
+      if sonsLen(ri) > 1: app(pl, " ")
       # beware of 'result = p(result)'. We always allocate a temporary:
       if d.k in {locTemp, locNone}:
         # We already got a temp. Great, special case it:
@@ -230,3 +244,21 @@ proc genNamedParamCall(p: BProc, t: PNode, d: var TLoc) =
     appf(p.s[cpsStmts], ";$n")
   emitAfterCallActions(aca)
 
+proc genCall(p: BProc, e: PNode, d: var TLoc) =
+  if e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags and
+      e.len >= 2:
+    genInfixCall(p, nil, e, d)
+  elif e.sons[0].kind == nkSym and sfNamedParamCall in e.sons[0].sym.flags:
+    genNamedParamCall(p, e, d)
+  else:
+    genPrefixCall(p, nil, e, d)
+
+proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
+  if ri.sons[0].kind == nkSym and sfInfixCall in ri.sons[0].sym.flags and
+      ri.len >= 2:
+    genInfixCall(p, le, ri, d)
+  elif ri.sons[0].kind == nkSym and sfNamedParamCall in ri.sons[0].sym.flags:
+    genNamedParamCall(p, ri, d)
+  else:
+    genPrefixCall(p, le, ri, d)
+
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 13d9637ad..ddd272fba 100755
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1378,13 +1378,6 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)")
   of mStrToStr: expr(p, e.sons[1], d)
   of mEnumToStr: genRepr(p, e, d)
-  of mAssert:
-    if optAssert in p.Options:
-      expr(p, e.sons[1], d)
-      line = toRope(toLinenumber(e.info))
-      filen = makeCString(ToFilename(e.info))
-      appcg(p, cpsStmts, "#internalAssert($1, $2, $3);$n",
-           [filen, line, rdLoc(d)])
   of mOf: genOf(p, e, d)
   of mNew: genNew(p, e)
   of mNewFinalize: genNewFinalize(p, e)
@@ -1635,11 +1628,6 @@ proc expr(p: BProc, e: PNode, d: var TLoc) =
      nkCallStrLit:
     if e.sons[0].kind == nkSym and e.sons[0].sym.magic != mNone:
       genMagicExpr(p, e, d, e.sons[0].sym.magic)
-    elif e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags and
-        e.len >= 2:
-      genInfixCall(p, e, d)
-    elif e.sons[0].kind == nkSym and sfNamedParamCall in e.sons[0].sym.flags:
-      genNamedParamCall(p, e, d)
     else:
       genCall(p, e, d)
   of nkCurly:
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index a994f27f3..108d7f071 100755
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -18,16 +18,16 @@ proc genVarTuple(p: BProc, n: PNode) =
   if n.kind != nkVarTuple: InternalError(n.info, "genVarTuple")
   var L = sonsLen(n)
   genLineDir(p, n)
-  initLocExpr(p, n.sons[L - 1], tup)
+  initLocExpr(p, n.sons[L-1], tup)
   var t = tup.t
-  for i in countup(0, L - 3): 
+  for i in countup(0, L-3): 
     var v = n.sons[i].sym
     if sfGlobal in v.flags: 
       assignGlobalVar(p, v)
       genObjectInit(p, cpsInit, v.typ, v.loc, true)
-    else: 
+    else:
       assignLocalVar(p, v)
-      initVariable(p, v)
+      initLocalVar(p, v, immediateAsgn=true)
     initLoc(field, locExpr, t.sons[i], tup.s)
     if t.n == nil: 
       field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)])
@@ -37,17 +37,25 @@ proc genVarTuple(p: BProc, n: PNode) =
                       [rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
     putLocIntoDest(p, v.loc, field)
 
+proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
+  if ri.kind in nkCallKinds and (ri.sons[0].kind != nkSym or
+                                 ri.sons[0].sym.magic == mNone):
+    genAsgnCall(p, le, ri, a)
+  else:
+    expr(p, ri, a)
+
 proc genSingleVar(p: BProc, a: PNode) =
   var v = a.sons[0].sym
+  var immediateAsgn = a.sons[2].kind != nkEmpty
   if sfGlobal in v.flags: 
     assignGlobalVar(p, v)
     genObjectInit(p, cpsInit, v.typ, v.loc, true)
-  else: 
+  else:
     assignLocalVar(p, v)
-    initVariable(p, v)
-  if a.sons[2].kind != nkEmpty: 
+    initLocalVar(p, v, immediateAsgn)
+  if immediateAsgn:
     genLineDir(p, a)
-    expr(p, a.sons[2], v.loc)
+    loadInto(p, a.sons[0], a.sons[2], v.loc)
 
 proc genVarStmt(p: BProc, n: PNode) = 
   for i in countup(0, sonsLen(n) - 1): 
@@ -658,7 +666,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
     InitLocExpr(p, e.sons[0], a)
     if fastAsgn: incl(a.flags, lfNoDeepCopy)
     assert(a.t != nil)
-    expr(p, e.sons[1], a)
+    loadInto(p, e.sons[0], e.sons[1], a)
   else:
     asgnFieldDiscriminant(p, e)
 
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 2018d7e6d..aa07f40aa 100755
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -14,7 +14,7 @@ import
   options, intsets,
   nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
   times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
-  rodutils, renderer, idgen, cgendata, ccgmerge, semfold
+  rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases
 
 when options.hasTinyCBackend:
   import tccgen
@@ -235,16 +235,17 @@ proc zeroVar(p: BProc, loc: TLoc, containsGCref: bool) =
       genRefAssign(p, loc, nilLoc, {afSrcIsNil})
     else:
       appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(loc)])
-  else: 
+  else:
     if containsGcref and p.WithInLoop > 0:
       appf(p.s[cpsInit], "memset((void*)$1, 0, sizeof($2));$n", 
            [addrLoc(loc), rdLoc(loc)])
+      genObjectInit(p, cpsInit, loc.t, loc, true)
       appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", 
            [addrLoc(loc), genTypeInfo(p.module, loc.t)])
     else:
       appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n", 
            [addrLoc(loc), rdLoc(loc)])
-    genObjectInit(p, cpsInit, loc.t, loc, true)
+      genObjectInit(p, cpsStmts, loc.t, loc, true)
 
 proc zeroTemp(p: BProc, loc: TLoc) = 
   if skipTypes(loc.t, abstractVarRange).Kind notin
@@ -259,15 +260,22 @@ proc zeroTemp(p: BProc, loc: TLoc) =
   else: 
     appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n", 
          [addrLoc(loc), rdLoc(loc)])
+    # XXX no object init necessary for temporaries?
     when false:
       appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", 
            [addrLoc(loc), genTypeInfo(p.module, loc.t)])
 
-proc initVariable(p: BProc, v: PSym) =
+proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
   if sfNoInit notin v.flags:
-    var b = containsGarbageCollectedRef(v.typ)
-    if b or v.ast == nil:
-      zeroVar(p, v.loc, b)
+    # we know it is a local variable and thus on the stack!
+    # If ``not immediateAsgn`` it is not initialized in a binding like
+    # ``var v = X`` and thus we need to init it. 
+    # If ``v`` contains a GC-ref we may pass it to ``unsureAsgnRef`` somehow
+    # which requires initialization. However this can really only happen if
+    # ``var v = X()`` gets transformed into ``X(&v)``. 
+    # Nowadays the logic in ccgcalls deals with this case however.
+    if not immediateAsgn:
+      zeroVar(p, v.loc, containsGarbageCollectedRef(v.typ))
     
 proc initTemp(p: BProc, tmp: var TLoc) = 
   if containsGarbageCollectedRef(tmp.t) or isInvalidReturnType(tmp.t):
@@ -534,13 +542,14 @@ proc genProcAux(m: BModule, prc: PSym) =
   assert(prc.ast != nil)
   if sfPure notin prc.flags and prc.typ.sons[0] != nil:
     var res = prc.ast.sons[resultPos].sym # get result symbol
-    if not isInvalidReturnType(prc.typ.sons[0]): 
+    if not isInvalidReturnType(prc.typ.sons[0]):
+      if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
       # declare the result symbol:
       assignLocalVar(p, res)
       assert(res.loc.r != nil)
       returnStmt = ropeff("return $1;$n", "ret $1$n", [rdLoc(res.loc)])
-      initVariable(p, res)
-    else: 
+      initLocalVar(p, res, immediateAsgn=false)
+    else:
       fillResult(res)
       assignParam(p, res)
       if skipTypes(res.typ, abstractInst).kind == tyArray: 
diff --git a/compiler/ecmasgen.nim b/compiler/ecmasgen.nim
index 588abfc93..76d4dde89 100755
--- a/compiler/ecmasgen.nim
+++ b/compiler/ecmasgen.nim
@@ -720,7 +720,8 @@ proc generateHeader(p: var TProc, typ: PType): PRope =
 const 
   nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit, 
     nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkStringToCString, 
-    nkCStringToString, nkCall, nkCommand, nkHiddenCallConv, nkCallStrLit}
+    nkCStringToString, nkCall, nkPrefix, nkPostfix, nkInfix, 
+    nkCommand, nkHiddenCallConv, nkCallStrLit}
 
 proc needsNoCopy(y: PNode): bool = 
   result = (y.kind in nodeKindsNeedNoCopy) or
@@ -1131,14 +1132,6 @@ proc genMagic(p: var TProc, n: PNode, r: var TCompRes) =
   of mLtStr: binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) < 0)")
   of mIsNil: unaryExpr(p, n, r, "", "$1 == null")
   of mEnumToStr: genRepr(p, n, r)
-  of mAssert:
-    if (optAssert in p.Options):
-      useMagic(p, "internalAssert")
-      gen(p, n.sons[1], a)
-      line = toRope(toLinenumber(n.info))
-      filen = makeCString(ToFilename(n.info))
-      appf(r.com, "if (!($3)) internalAssert($1, $2)",
-           [filen, line, mergeExpr(a)])
   of mNew, mNewFinalize: genNew(p, n, r)
   of mSizeOf: r.res = toRope(getSize(n.sons[1].typ))
   of mChr, mArrToSeq: gen(p, n.sons[1], r)      # nothing to do
@@ -1402,7 +1395,7 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) =
     else: r.res = toRope(f.ToStrMaxPrecision)
   of nkBlockExpr: genBlock(p, n, r)
   of nkIfExpr: genIfExpr(p, n, r)
-  of nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit: 
+  of nkCallKinds: 
     if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone): 
       genMagic(p, n, r)
     else: 
diff --git a/compiler/evals.nim b/compiler/evals.nim
index fff58b7f4..2ca0f3faf 100755
--- a/compiler/evals.nim
+++ b/compiler/evals.nim
@@ -695,13 +695,7 @@ proc evalNewSeq(c: PEvalContext, n: PNode): PNode =
   for i in countup(0, L-1): 
     a.sons[i] = getNullValue(t.sons[0], n.info)
   result = emptyNode
-
-proc evalAssert(c: PEvalContext, n: PNode): PNode = 
-  result = evalAux(c, n.sons[1], {})
-  if isSpecial(result): return 
-  if getOrdValue(result) != 0: result = emptyNode
-  else: stackTrace(c, n, errAssertionFailed)
-  
+ 
 proc evalIncl(c: PEvalContext, n: PNode): PNode = 
   result = evalAux(c, n.sons[1], {efLValue})
   if isSpecial(result): return 
@@ -876,7 +870,6 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
   of mOf: result = evalOf(c, n)
   of mSizeOf: result = raiseCannotEval(c, n)
   of mHigh: result = evalHigh(c, n)
-  of mAssert: result = evalAssert(c, n)
   of mExit: result = evalExit(c, n)
   of mNew, mNewFinalize: result = evalNew(c, n)
   of mNewSeq: result = evalNewSeq(c, n)
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index d4ea3226d..a291d4741 100755
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -23,7 +23,7 @@ const
     wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, 
     wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge, 
     wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
-    wNoStackFrame, wError, wDiscardable}
+    wNoStackFrame, wError, wDiscardable, wNoInit}
   converterPragmas* = procPragmas
   methodPragmas* = procPragmas
   macroPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, 
diff --git a/compiler/sem.nim b/compiler/sem.nim
index a4a0ba1bc..d38a547c2 100755
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -14,7 +14,7 @@ import
   wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
   magicsys, parser, nversion, semdata, nimsets, semfold, importer,
   procfind, lookups, rodread, pragmas, passes, semtypinst, sigmatch, suggest,
-  semthreads, intsets, transf, evals, idgen
+  semthreads, intsets, transf, evals, idgen, aliases
 
 proc semPass*(): TPass
 # implementation
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 7bb6f26e0..a5093f567 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -453,6 +453,14 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
         skipTypes(t.sons[i], abstractInst).kind == tyVar:
       n.sons[i] = analyseIfAddressTaken(c, n.sons[i])
   
+
+proc expectStringArg(c: PContext, n: PNode, i: int): PNode =
+  result = c.semAndEvalConstExpr(n.sons[i+1])
+  if result.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
+    GlobalError(result.info, errStringLiteralExpected)
+  
+include semmagic
+
 proc semDirectCallAnalyseEffects(c: PContext, n: PNode,
                                  flags: TExprFlags): PNode =
   if efWantIterator in flags:
@@ -520,6 +528,8 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
                   renderTree(n, {renderNoComments}))
   fixAbstractType(c, result)
   analyseIfAddressTakenInCall(c, result)
+  if result.sons[0].kind == nkSym and result.sons[0].sym.magic != mNone:
+    result = magicsAfterOverloadResolution(c, result, flags)
 
 proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = 
   # this seems to be a hotspot in the compiler!
@@ -530,6 +540,8 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
     if result == nil: GlobalError(n.Info, errGenerated, getNotFoundError(c, n))
   fixAbstractType(c, result)
   analyseIfAddressTakenInCall(c, result)
+  if result.sons[0].sym.magic != mNone:
+    result = magicsAfterOverloadResolution(c, result, flags)
 
 proc buildStringify(c: PContext, arg: PNode): PNode = 
   if arg.typ != nil and skipTypes(arg.typ, abstractInst).kind == tyString:
@@ -914,12 +926,6 @@ proc setMs(n: PNode, s: PSym): PNode =
   n.sons[0] = newSymNode(s)
   n.sons[0].info = n.info
 
-proc expectStringArg(c: PContext, n: PNode, i: int): PNode =
-  result = c.semAndEvalConstExpr(n.sons[i+1])
-
-  if result.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
-    GlobalError(result.info, errStringLiteralExpected)
-
 proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym =
   ## The argument to the proc should be nkCall(...) or similar
   ## Returns the macro/template symbol
@@ -954,21 +960,6 @@ proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
   else:
     result = semDirectOp(c, n, flags)
 
-proc semSlurp(c: PContext, n: PNode, flags: TExprFlags): PNode = 
-  if sonsLen(n) == 2:
-    var a = expectStringArg(c, n, 0)
-    try:
-      var filename = a.strVal.FindFile
-      var content = readFile(filename)
-      result = newStrNode(nkStrLit, content)
-      result.typ = getSysType(tyString)
-      result.info = n.info
-      c.slurpedFiles.add(filename)
-    except EIO:
-      GlobalError(a.info, errCannotOpenFile, a.strVal)
-  else:
-    result = semDirectOp(c, n, flags)
-
 proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = 
   # this is a hotspot in the compiler!
   result = n
@@ -991,14 +982,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
       result = semAsgn(c, result)
     else:
       result = semDirectOp(c, n, flags)
-  of mSlurp: result = semSlurp(c, n, flags)
   of mExpandToAst: result = semExpandToAst(c, n, s, flags)
-  of mAstToStr:
-    if sonsLen(n) == 2:
-      result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
-      result.typ = getSysType(tyString)
-    else:
-      result = semDirectOp(c, n, flags)
   else: result = semDirectOp(c, n, flags)
 
 proc semIfExpr(c: PContext, n: PNode): PNode = 
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index b2e2f2277..0eb05a055 100755
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -204,7 +204,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
     result = newIntNodeT(Ord(
       testCompileOptionArg(getStr(a), getStr(b), n.info)), n)
   of mNewString, mNewStringOfCap, 
-     mExit, mInc, ast.mDec, mEcho, mAssert, mSwap, mAppendStrCh, 
+     mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh, 
      mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq, 
      mParseExprToAst, mParseStmtToAst, mExpandToAst,
      mNLen..mNError, mEqRef: 
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
new file mode 100644
index 000000000..696988fd3
--- /dev/null
+++ b/compiler/semmagic.nim
@@ -0,0 +1,38 @@
+#
+#
+#           The Nimrod Compiler
+#        (c) Copyright 2011 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This include file implements the semantic checking for magics.
+
+proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  var r = isPartOf(n[1], n[2])
+  result = newIntNodeT(ord(r), n)
+  
+proc semSlurp(c: PContext, n: PNode, flags: TExprFlags): PNode = 
+  assert sonsLen(n) == 2
+  var a = expectStringArg(c, n, 0)
+  try:
+    var filename = a.strVal.FindFile
+    var content = readFile(filename)
+    result = newStrNode(nkStrLit, content)
+    result.typ = getSysType(tyString)
+    result.info = n.info
+    c.slurpedFiles.add(filename)
+  except EIO:
+    GlobalError(a.info, errCannotOpenFile, a.strVal)
+
+proc magicsAfterOverloadResolution(c: PContext, n: PNode, 
+                                   flags: TExprFlags): PNode =
+  case n[0].sym.magic
+  of mSlurp: result = semSlurp(c, n, flags)
+  of mIsPartOf: result = semIsPartOf(c, n, flags)
+  of mAstToStr:
+    result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
+    result.typ = getSysType(tyString)
+  else: result = n
+
diff --git a/compiler/types.nim b/compiler/types.nim
index 6ce4c6e48..d3f2bd1b5 100755
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -1024,7 +1024,6 @@ proc computeSize(typ: PType): biggestInt =
 proc getReturnType*(s: PSym): PType =
   # Obtains the return type of a iterator/proc/macro/template
   assert s.kind in {skProc, skTemplate, skMacro, skIterator}
-  # XXX ask Zahary if this change broke something
   result = s.typ.sons[0]
 
 proc getSize(typ: PType): biggestInt = 
diff --git a/doc/manual.txt b/doc/manual.txt
index 164410a68..97af7fe2a 100755
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -1584,6 +1584,11 @@ The implicit initialization can be avoided for optimization reasons with the
   var

     a {.noInit.}: array [0..1023, char] 

 

+If a proc is annotated with the ``noinit`` pragma this refers to its implicit

+``result`` variable:

+

+.. code-block:: nimrod

+  proc returnUndefinedValue: int {.noinit.} = nil

 

 

 let statement

@@ -2849,6 +2854,7 @@ exported.
 The algorithm for compiling modules is:

 

 - compile the whole module as usual, following import statements recursively

+

 - if there is a cycle only import the already parsed symbols (that are

   exported); if an unknown identifier occurs then abort

 

diff --git a/lib/pure/actors.nim b/lib/pure/actors.nim
index 2510bb8cd..c07adfd93 100644
--- a/lib/pure/actors.nim
+++ b/lib/pure/actors.nim
@@ -11,6 +11,8 @@
 ## a channel as its inbox. This module requires the ``--threads:on``
 ## command line switch.
 
+from os import sleep
+
 type
   TTask*[TIn, TOut] = object{.pure, final.}
     when TOut isnot void:
@@ -29,7 +31,7 @@ type
 proc spawn*[TIn, TOut](action: proc(
     self: PActor[TIn, TOut]){.thread.}): PActor[TIn, TOut] =
   ## creates an actor; that is a thread with an inbox. The caller MUST call
-  ## ``join`` because that also frees the associated resources with the actor.
+  ## ``join`` because that also frees the actor's associated resources.
   result = cast[PActor[TIn, TOut]](allocShared0(sizeof(result[])))
   open(result.i)
   createThread(result.t, action, result)
@@ -42,6 +44,10 @@ proc running*[TIn, TOut](a: PActor[TIn, TOut]) =
   ## returns true if the actor `a` is running.
   result = running(a.t)
 
+proc ready*[TIn, TOut](a: PActor[TIn, TOut]): bool =
+  ## returns true if the actor `a` is ready to process new messages.
+  result = ready(a.i)
+
 proc join*[TIn, TOut](a: PActor[TIn, TOut]) =
   ## joins an actor.
   joinThread(a.t)
@@ -111,17 +117,35 @@ proc createActorPool*[TIn, TOut](a: var TActorPool[TIn, TOut], poolSize = 4) =
   for i in 0 .. < a.actors.len:
     a.actors[i] = spawn(poolWorker[TIn, TOut])
 
-proc join*[TIn, TOut](a: var TActorPool[TIn, TOut]) =
-  ## waits for each actor in the actor pool `a` to finish and frees the
+proc sync*[TIn, TOut](a: var TActorPool[TIn, TOut], polling=50) =
+  ## waits for every actor of `a` to finish with its work. Currently this is
+  ## implemented as polling every `polling` ms. This will change in a later
+  ## version, however.
+  while true:
+    var wait = false
+    for i in 0..high(a.actors):
+      if not a.actors[i].i.ready: 
+        wait = true
+        break
+    if not wait: break
+    sleep(polling)
+
+proc terminate*[TIn, TOut](a: var TActorPool[TIn, TOut]) =
+  ## terminates each actor in the actor pool `a` and frees the
   ## resources attached to `a`.
   var t: TTask[TIn, TOut]
   t.shutdown = true
-  for i in 0 .. < a.actors.len: send(a.actors[i].i, t)
-  for i in 0 .. < a.actors.len: join(a.actors[i])
+  for i in 0.. <a.actors.len: send(a.actors[i].i, t)
+  for i in 0.. <a.actors.len: join(a.actors[i])
   when TOut isnot void:
     close(a.outputs)
   a.actors = nil
 
+proc join*[TIn, TOut](a: var TActorPool[TIn, TOut]) =
+  ## short-cut for `sync` and then `terminate`.
+  sync(a)
+  terminate(a)
+
 template setupTask =
   t.action = action
   shallowCopy(t.data, input)
@@ -135,7 +159,7 @@ template schedule =
       return
   # no thread ready :-( --> send message to the thread which has the least
   # messages pending:
-  var minIdx = 0
+  var minIdx = -1
   var minVal = high(int)
   for i in 0..high(p.actors):
     var curr = p.actors[i].i.peek
@@ -143,10 +167,13 @@ template schedule =
       # ok, is ready now:
       p.actors[i].i.send(t)
       return
-    if curr < minVal:
+    if curr < minVal and curr >= 0:
       minVal = curr
       minIdx = i
-  p.actors[minIdx].i.send(t)
+  if minIdx >= 0:
+    p.actors[minIdx].i.send(t)
+  else:
+    raise newException(EDeadThread, "cannot send message; thread died")
 
 proc spawn*[TIn, TOut](p: var TActorPool[TIn, TOut], input: TIn,
                        action: proc (input: TIn): TOut {.thread.}
diff --git a/lib/system.nim b/lib/system.nim
index c7e26230a..8a99781cc 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -2071,14 +2071,24 @@ proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.}
   ## converts the AST of `x` into a string representation. This is very useful
   ## for debugging.
   
+proc raiseAssert(msg: string) {.noinline.} =
+  raise newException(EAssertionFailed, msg)
+  
 template assert*(cond: expr, msg = "") =
   ## provides a means to implement `programming by contracts`:idx: in Nimrod.
   ## ``assert`` evaluates expression ``cond`` and if ``cond`` is false, it
   ## raises an ``EAssertionFailure`` exception. However, the compiler may
   ## not generate any code at all for ``assert`` if it is advised to do so.
   ## Use ``assert`` for debugging purposes only.
+  bind raiseAssert
   when compileOption("assertions"):
     if not cond:
-      raise newException(EAssertionFailed, astToStr(cond) & ' ' & msg)
-
+      raiseAssert(astToStr(cond) & ' ' & msg)
+
+template doAssert*(cond: expr, msg = "") =
+  ## same as `assert' but is always turned on and not affected by the
+  ## ``--assertions`` command line switch.
+  bind raiseAssert
+  if not cond:
+    raiseAssert(astToStr(cond) & ' ' & msg)
 
diff --git a/lib/system/channels.nim b/lib/system/channels.nim
index fe93d6840..47fa5b2e5 100755
--- a/lib/system/channels.nim
+++ b/lib/system/channels.nim
@@ -222,11 +222,14 @@ proc recv*[TMsg](c: var TChannel[TMsg]): TMsg =
   llRecv(q, addr(result), cast[PNimType](getTypeInfo(result)))

 

 proc peek*[TMsg](c: var TChannel[TMsg]): int =

-  ## returns the current number of messages in the channel `c`.

+  ## returns the current number of messages in the channel `c`. Returns -1

+  ## if the channel has been closed.

   var q = cast[PRawChannel](addr(c))

   if q.mask != ChannelDeadMask:

     lockChannel(q):

       result = q.count

+  else:

+    result = -1

 

 proc open*[TMsg](c: var TChannel[TMsg]) =

   ## opens a channel `c` for inter thread communication.

diff --git a/tests/run/tpegs.nim b/tests/run/tpegs.nim
index 64c547b24..8fe302073 100755
--- a/tests/run/tpegs.nim
+++ b/tests/run/tpegs.nim
@@ -1669,25 +1669,25 @@ proc escapePeg*(s: string): string =
   if inQuote: result.add('\'')
 
 when isMainModule:
-  assert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27"
-  #assert match("(a b c)", peg"'(' @ ')'")
-  assert match("W_HI_Le", peg"\y 'while'")
-  assert(not match("W_HI_L", peg"\y 'while'"))
-  assert(not match("W_HI_Le", peg"\y v'while'"))
-  assert match("W_HI_Le", peg"y'while'")
+  doAssert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27"
+  #doAssert match("(a b c)", peg"'(' @ ')'")
+  doAssert match("W_HI_Le", peg"\y 'while'")
+  doAssert(not match("W_HI_L", peg"\y 'while'"))
+  doAssert(not match("W_HI_Le", peg"\y v'while'"))
+  doAssert match("W_HI_Le", peg"y'while'")
   
-  assert($ +digits == $peg"\d+")
-  assert "0158787".match(peg"\d+")
-  assert "ABC 0232".match(peg"\w+\s+\d+")
-  assert "ABC".match(peg"\d+ / \w+")
+  doAssert($ +digits == $peg"\d+")
+  doAssert "0158787".match(peg"\d+")
+  doAssert "ABC 0232".match(peg"\w+\s+\d+")
+  doAssert "ABC".match(peg"\d+ / \w+")
 
   for word in split("00232this02939is39an22example111", peg"\d+"):
     writeln(stdout, word)
 
-  assert matchLen("key", ident) == 3
+  doAssert matchLen("key", ident) == 3
 
   var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident)
-  assert matchLen("key1=  cal9", pattern) == 11
+  doAssert matchLen("key1=  cal9", pattern) == 11
   
   var ws = newNonTerminal("ws", 1, 1)
   ws.rule = *whitespace
@@ -1698,24 +1698,24 @@ when isMainModule:
   
   var c: TCaptures
   var s = "a+b +  c +d+e+f"
-  assert rawMatch(s, expr.rule, 0, c) == len(s)
+  doAssert rawMatch(s, expr.rule, 0, c) == len(s)
   var a = ""
   for i in 0..c.ml-1:
     a.add(substr(s, c.matches[i][0], c.matches[i][1]))
-  assert a == "abcdef"
+  doAssert a == "abcdef"
   #echo expr.rule
 
   #const filename = "lib/devel/peg/grammar.txt"
   #var grammar = parsePeg(newFileStream(filename, fmRead), filename)
   #echo "a <- [abc]*?".match(grammar)
-  assert find("_____abc_______", term("abc"), 2) == 5
-  assert match("_______ana", peg"A <- 'ana' / . A")
-  assert match("abcs%%%", peg"A <- ..A / .A / '%'")
+  doAssert find("_____abc_______", term("abc"), 2) == 5
+  doAssert match("_______ana", peg"A <- 'ana' / . A")
+  doAssert match("abcs%%%", peg"A <- ..A / .A / '%'")
 
   if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}":
-    assert matches[0] == "abc"
+    doAssert matches[0] == "abc"
   else:
-    assert false
+    doAssert false
   
   var g2 = peg"""S <- A B / C D
                  A <- 'a'+
@@ -1723,44 +1723,44 @@ when isMainModule:
                  C <- 'c'+
                  D <- 'd'+
               """
-  assert($g2 == "((A B) / (C D))")
-  assert match("cccccdddddd", g2)
-  assert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
+  doAssert($g2 == "((A B) / (C D))")
+  doAssert match("cccccdddddd", g2)
+  doAssert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
          "var1<-keykey; var2<-key2key2")
-  assert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}")
+  doAssert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}")
 
   if "aaaaaa" =~ peg"'aa' !. / ({'a'})+":
-    assert matches[0] == "a"
+    doAssert matches[0] == "a"
   else:
-    assert false
+    doAssert false
     
   var matches: array[0..5, string]
   if match("abcdefg", peg"c {d} ef {g}", matches, 2): 
-    assert matches[0] == "d"
-    assert matches[1] == "g"
+    doAssert matches[0] == "d"
+    doAssert matches[1] == "g"
   else:
-    assert false
+    doAssert false
 
   for x in findAll("abcdef", peg"{.}", 3):
     echo x
     
   if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')":
-    assert matches[0] == "f"
-    assert matches[1] == "a, b"
+    doAssert matches[0] == "f"
+    doAssert matches[1] == "a, b"
   else:
-    assert false
+    doAssert false
   
-  assert match("eine übersicht und außerdem", peg"(\letter \white*)+")
+  doAssert match("eine übersicht und außerdem", peg"(\letter \white*)+")
   # ß is not a lower cased letter?!
-  assert match("eine übersicht und auerdem", peg"(\lower \white*)+")
-  assert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+")
-  assert(not match("456678", peg"(\letter)+"))
+  doAssert match("eine übersicht und auerdem", peg"(\lower \white*)+")
+  doAssert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+")
+  doAssert(not match("456678", peg"(\letter)+"))
 
-  assert("var1 = key; var2 = key2".replacef(
+  doAssert("var1 = key; var2 = key2".replacef(
     peg"\skip(\s*) {\ident}'='{\ident}", "$1<-$2$2") ==
          "var1<-keykey;var2<-key2key2")
 
-  assert match("prefix/start", peg"^start$", 7)
+  doAssert match("prefix/start", peg"^start$", 7)
   
   # tricky test to check for false aliasing:
   block:
diff --git a/tests/run/tuserassert.nim b/tests/run/tuserassert.nim
index 958da2fe1..cf12c4e8b 100644
--- a/tests/run/tuserassert.nim
+++ b/tests/run/tuserassert.nim
@@ -5,7 +5,6 @@ discard """
 template myAssert(cond: expr) = 
   when rand(3) < 2:
     let c = cond.astToStr
-    {.warning: "code activated: " & c.}
     if not cond:
       echo c, "ugh"
   
diff --git a/tests/specials.nim b/tests/specials.nim
index 1f3013e90..a1aa1bc5a 100644
--- a/tests/specials.nim
+++ b/tests/specials.nim
@@ -118,6 +118,7 @@ proc runThreadTests(r: var TResults, options: string) =
   
   test "tactors"
   test "threadex"
+  test "trecursive_actor"
   #test "threadring"
   #test "tthreadanalysis"
   #test "tthreadsort"
diff --git a/tests/threads/trecursive_actor.nim b/tests/threads/trecursive_actor.nim
new file mode 100644
index 000000000..e2774704c
--- /dev/null
+++ b/tests/threads/trecursive_actor.nim
@@ -0,0 +1,19 @@
+discard """
+  outputsub: "0"
+"""
+
+import actors
+
+var
+  a: TActorPool[int, void]
+createActorPool(a)
+
+proc task(i: int) {.thread.} =
+  echo i
+  if i != 0: a.spawn (i-1, task)
+
+# count from 9 till 0 and check 0 is somewhere in the output
+a.spawn(9, task)
+a.join()
+
+
diff --git a/todo.txt b/todo.txt
index 0ff5967c0..33dc52bf9 100755
--- a/todo.txt
+++ b/todo.txt
@@ -1,7 +1,9 @@
 version 0.8.14
 ==============
 
-- find a proper bugfix for C compilers optimizing away stack roots
+- implement a proper bugfix for C compilers optimizing away stack roots
+
+- cleanup file path handling in the compiler
 - warning for implicit openArray -> varargs convention
 - implement explicit varargs; **but** ``len(varargs)`` problem remains! 
   --> solve by implicit conversion from varargs to openarray
@@ -36,9 +38,6 @@ version 0.9.0
 Bugs
 ----
 - bug: generic assign still buggy
-  - Optimization: If we use a temporary for the result anyway the code gen
-    should make use of this fact to generate better code...
-  - bug: memset() without type field initialization?
   - special case the generic assign that needs to care about case objects
 
 - bug: returning a tyVar does not mean it is save to return it:
@@ -124,7 +123,6 @@ Low priority
     need to recompile clients; er ... what about templates, macros or anything
     that has inlining semantics?
 - codegen should use "NIM_CAST" macro and respect aliasing rules for GCC
-- remove unused mAssert magic
 
 Version 2
 =========
diff --git a/web/news.txt b/web/news.txt
index b4c76cdc3..22e0377c5 100755
--- a/web/news.txt
+++ b/web/news.txt
@@ -29,7 +29,7 @@ Changes affecting backwards compatibility
   ``os.iterOverEnvironment``, ``os.pcDirectory``, ``os.pcLinkToDirectory``,
   ``os.SplitPath``, ``os.extractDir``, ``os.SplitFilename``, 
   ``os.extractFileTrunk``, ``os.extractFileExt``, ``osproc.executeProcess``,
-  ``osproc.executeCommand``. 
+  ``osproc.executeCommand``.
 - Removed deprecated ``parseopt.init``, ``parseopt.getRestOfCommandLine``.
 - Moved ``strutils.validEmailAddress`` to ``matchers.validEmailAddress``.
 - The pointer dereference operator ``^`` has been removed, so that ``^``
@@ -53,8 +53,8 @@ Changes affecting backwards compatibility
   because they should not be used directly anymore. 
   Wrapper procs have been created that should be used instead.
 - ``export`` is now a keyword.
-- ``assert`` is now implemented in pure Nimrod; it's easy to implement your
-  own assertion schemes now.
+- ``assert`` is now implemented in pure Nimrod as a template; it's easy 
+  to implement your own assertion templates with ``system.astToStr``.
 
 
 Language Additions
@@ -112,6 +112,7 @@ Compiler Additions
 - Added ``--import:file`` and ``--include:file`` configuration options
   for specifying modules that will be automatically imported/incluced.
 - ``nimrod i`` can now optionally be given a module to execute.
+- The compiler now performs a simple aliases analysis to generate better code.
 
 
 Library Additions
@@ -128,7 +129,7 @@ Library Additions
 - Added ``system.program_result``.
 - Added ``xmltree.innerText``.
 - Added ``os.isAbsolute``, ``os.dynLibFormat``, ``os.isRootDir``,
-   ``os.parentDirs``.
+  ``os.parentDirs``.
 - Added ``parseutils.interpolatedFragments``.
 - Added ``macros.treeRepr``, ``macros.lispRepr``, ``macros.dumpTree``, 
   ``macros.dumpLisp``, ``macros.parseExpr``, ``macros.parseStmt``, 
@@ -142,7 +143,7 @@ Library Additions
   and ``exec`` on Posix systems. Define the symbol ``useFork`` to revert to
   the old implementation.
 - Added ``intsets.assign``.
-- Added ``system.astToStr`` and ``system.rand``.
+- Added ``system.astToStr`` and ``system.rand``, ``system.doAssert``.
 
 
 2011-07-10 Version 0.8.12 released