summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-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
15 files changed, 363 insertions, 142 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 =