summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim29
-rw-r--r--compiler/guards.nim346
-rw-r--r--compiler/magicsys.nim16
-rw-r--r--compiler/msgs.nim9
-rw-r--r--compiler/nimrod.ini1
-rw-r--r--compiler/parampatterns.nim2
-rw-r--r--compiler/pragmas.nim10
-rw-r--r--compiler/semexprs.nim25
-rw-r--r--compiler/sempass2.nim68
-rw-r--r--compiler/semstmts.nim2
-rw-r--r--compiler/semtypes.nim67
-rw-r--r--compiler/semtypinst.nim2
-rw-r--r--compiler/transf.nim7
-rw-r--r--compiler/trees.nim3
-rw-r--r--compiler/wordrecg.nim4
15 files changed, 531 insertions, 60 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 6e5a17d99..f4b1b84f5 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -353,7 +353,7 @@ type
     nfSem       # node has been checked for semantics
 
   TNodeFlags* = set[TNodeFlag]
-  TTypeFlag* = enum   # keep below 32 for efficiency reasons (now: 19)
+  TTypeFlag* = enum   # keep below 32 for efficiency reasons (now: 23)
     tfVarargs,        # procedure has C styled varargs
     tfNoSideEffect,   # procedure type does not allow side effects
     tfFinal,          # is the object final?
@@ -380,7 +380,13 @@ type
     tfByRef,          # pass object/tuple by reference (C backend)
     tfIterator,       # type is really an iterator, not a tyProc
     tfShared,         # type is 'shared'
-    tfNotNil          # type cannot be 'nil'
+    tfNotNil,         # type cannot be 'nil'
+    
+    tfNeedsInit,      # type constains a "not nil" constraint somewhere or some
+                      # other type so that it requires inititalization
+    tfHasShared,      # type constains a "shared" constraint modifier somewhere
+    tfHasMeta,        # type has "typedesc" or "expr" somewhere
+    tfHasGCedMem,     # type contains GC'ed memory
 
   TTypeFlags* = set[TTypeFlag]
 
@@ -1168,14 +1174,25 @@ proc newSons(father: PNode, length: int) =
   else:
     setlen(father.sons, length)
 
-proc addSon*(father, son: PType) {.deprecated.} =
-  if isNil(father.sons): father.sons = @[]
-  add(father.sons, son)
-  #assert((father.kind != tyGenericInvokation) or (son.kind != tyGenericInst))
+proc propagateToOwner*(owner, elem: PType) =
+  owner.flags = owner.flags + (elem.flags * {tfNeedsInit, tfHasShared, 
+                                             tfHasMeta, tfHasGCedMem})
+  if tfNotNil in elem.flags:
+    owner.flags.incl tfNeedsInit
+    
+  if tfShared in elem.flags:
+    owner.flags.incl tfHasShared
+  
+  if elem.kind in {tyExpr, tyTypeDesc}:
+    owner.flags.incl tfHasMeta
+  elif elem.kind in {tyString, tyRef, tySequence} or
+      elem.kind == tyProc and elem.callConv == ccClosure:
+    owner.flags.incl tfHasGCedMem
 
 proc rawAddSon*(father, son: PType) =
   if isNil(father.sons): father.sons = @[]
   add(father.sons, son)
+  if not son.isNil: propagateToOwner(father, son)
 
 proc addSon(father, son: PNode) = 
   assert son != nil
diff --git a/compiler/guards.nim b/compiler/guards.nim
new file mode 100644
index 000000000..6d0bf6bc6
--- /dev/null
+++ b/compiler/guards.nim
@@ -0,0 +1,346 @@
+#
+#
+#           The Nimrod Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements the 'implies' relation for guards.
+
+import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer
+
+const
+  someEq = {mEqI, mEqI64, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc, 
+    mEqUntracedRef, mEqStr, mEqSet, mEqCString}
+  
+  # set excluded here as the semantics are vastly different:
+  someLe = {mLeI, mLeI64, mLeF64, mLeU, mLeU64, mLeEnum,  
+            mLeCh, mLeB, mLePtr, mLeStr}
+  someLt = {mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum, 
+            mLtCh, mLtB, mLtPtr, mLtStr}
+
+  someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq}
+
+  someIn = {mInRange, mInSet}
+
+proc isValue(n: PNode): bool = n.kind in {nkCharLit..nkNilLit}
+proc isLocation(n: PNode): bool = not n.isValue
+#n.kind in {nkSym, nkBracketExpr, nkDerefExpr, nkHiddenDeref, nkDotExpr}
+
+proc isLet(n: PNode): bool =
+  if n.kind == nkSym:
+    # XXX allow skResult, skVar here if not re-bound
+    if n.sym.kind in {skLet, skTemp, skForVar}:
+      result = true
+    elif n.sym.kind == skParam and skipTypes(n.sym.typ, 
+                                             abstractInst).kind != tyVar:
+      result = true
+
+proc isLetLocation(m: PNode): bool =
+  var n = m
+  while true:
+    case n.kind
+    of nkDotExpr, nkCheckedFieldExpr, nkObjUpConv, nkObjDownConv:
+      n = n.sons[0]
+    of nkBracketExpr:
+      if isConstExpr(n.sons[1]) or isLet(n.sons[1]):
+        n = n.sons[0]
+      else: return
+    of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+      n = n.sons[1]
+    else:
+      break
+  result = n.isLet
+
+proc neg(n: PNode): PNode =
+  if n.getMagic == mNot:
+    result = n.sons[1]
+  else:
+    result = newNodeI(nkCall, n.info, 2)
+    result.sons[0] = newSymNode(getSysMagic("not", mNot))
+    result.sons[1] = n
+
+proc usefulFact(n: PNode): PNode =
+  case n.getMagic
+  of someEq+someLe+someLt:
+    if isLetLocation(n.sons[1]) or n.len == 3 and isLetLocation(n.sons[2]):
+      # XXX algebraic simplifications!  'i-1 < a.len' --> 'i < a.len+1'
+      result = n
+  of someIn, mIsNil:
+    if isLetLocation(n.sons[1]):
+      result = n
+  of mAnd:
+    let
+      a = usefulFact(n.sons[1])
+      b = usefulFact(n.sons[2])
+    if a != nil and b != nil:
+      result = newNodeI(nkCall, n.info, 3)
+      result.sons[0] = newSymNode(getSysMagic("and", mAnd))
+      result.sons[1] = a
+      result.sons[2] = b
+    elif a != nil:
+      result = a
+    elif b != nil:
+      result = b
+  of mNot:
+    case n.sons[1].getMagic
+    of mNot:
+      # normalize 'not (not a)' into 'a':
+      result = usefulFact(n.sons[1].sons[1])
+    of mOr:
+      # not (a or b) --> not a and not b
+      let n = n.sons[1]
+      let
+        a = usefulFact(n.sons[1])
+        b = usefulFact(n.sons[2])
+      if a != nil and b != nil:
+        result = newNodeI(nkCall, n.info, 3)
+        result.sons[0] = newSymNode(getSysMagic("and", mAnd))
+        result.sons[1] = a.neg
+        result.sons[2] = b.neg
+    else:
+      let a = usefulFact(n.sons[1])
+      if a != nil: result = n
+  of mOr:
+    # 'or' sucks! (p.isNil or q.isNil) --> hard to do anything
+    # with that knowledge...
+    # DeMorgan helps a little though: 
+    #   not a or not b --> not (a and b)
+    #  (x == 3) or (y == 2)  ---> not ( not (x==3) and not (y == 2))
+    #  not (x != 3 and y != 2)
+    let
+      a = usefulFact(n.sons[1])
+      b = usefulFact(n.sons[2])
+    if a != nil and b != nil:
+      result = newNodeI(nkCall, n.info, 3)
+      result.sons[0] = newSymNode(getSysMagic("and", mAnd))
+      result.sons[1] = a.neg
+      result.sons[2] = b.neg
+      result = result.neg
+  elif n.kind == nkSym and n.sym.kind == skLet:
+    # consider:
+    #   let a = 2 < x
+    #   if a:
+    #     ...
+    # We make can easily replace 'a' by '2 < x' here:
+    result = usefulFact(n.sym.ast)
+  elif n.kind == nkStmtListExpr:
+    result = usefulFact(n.lastSon)
+
+type
+  TModel* = seq[PNode] # the "knowledge base"
+
+proc addFact*(m: var TModel, n: PNode) =
+  let n = usefulFact(n)
+  if n != nil: m.add n
+
+proc addFactNeg*(m: var TModel, n: PNode) = addFact(m, n.neg)
+
+proc sameTree(a, b: PNode): bool = 
+  result = false
+  if a == b:
+    result = true
+  elif (a != nil) and (b != nil) and (a.kind == b.kind):
+    case a.kind
+    of nkSym: result = a.sym == b.sym
+    of nkIdent: result = a.ident.id == b.ident.id
+    of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
+    of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
+    of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
+    of nkType: result = a.typ == b.typ
+    of nkEmpty, nkNilLit: result = true
+    else:
+      if sonsLen(a) == sonsLen(b):
+        for i in countup(0, sonsLen(a) - 1):
+          if not sameTree(a.sons[i], b.sons[i]): return
+        result = true
+
+proc valuesUnequal(a, b: PNode): bool =
+  if a.isValue and b.isValue:
+    result = not SameValue(a, b)
+
+type
+  TImplication* = enum
+    impUnknown, impNo, impYes  
+
+proc impliesEq(fact, eq: PNode): TImplication =
+  let (loc, val) = if isLocation(eq.sons[1]): (1, 2) else: (2, 1)
+  
+  case fact.sons[0].sym.magic
+  of someEq:
+    if sameTree(fact.sons[1], eq.sons[loc]):
+      # this is not correct; consider:  a == b;  a == 1 --> unknown!
+      if sameTree(fact.sons[2], eq.sons[val]): result = impYes
+      elif valuesUnequal(fact.sons[2], eq.sons[val]): result = impNo
+    elif sameTree(fact.sons[2], eq.sons[loc]):
+      if sameTree(fact.sons[1], eq.sons[val]): result = impYes
+      elif valuesUnequal(fact.sons[1], eq.sons[val]): result = impNo
+  of mInSet:
+    if sameTree(fact.sons[1], eq.sons[loc]) and isValue(eq.sons[val]):
+      if inSet(fact.sons[2], eq.sons[val]): result = impYes
+      else: result = impNo
+  of mIsNil:
+    if sameTree(fact.sons[1], eq.sons[loc]):
+      if eq.sons[val].kind == nkNilLit:
+        result = impYes
+  of mNot, mOr, mAnd: internalError(eq.info, "impliesEq")
+  else: nil
+  
+proc impliesIsNil(fact, eq: PNode): TImplication =
+  case fact.sons[0].sym.magic
+  of someEq:
+    if sameTree(fact.sons[1], eq.sons[1]):
+      if fact.sons[2].kind == nkNilLit: result = impYes
+    elif sameTree(fact.sons[2], eq.sons[1]):
+      if fact.sons[1].kind == nkNilLit: result = impYes
+  of mIsNil:
+    if sameTree(fact.sons[1], eq.sons[1]):
+      result = impYes
+  of mNot, mOr, mAnd: internalError(eq.info, "impliesIsNil")
+  else: nil
+
+proc pred(n: PNode): PNode =
+  if n.kind in {nkCharLit..nkUInt64Lit} and n.intVal != low(biggestInt):
+    result = copyNode(n)
+    dec result.intVal
+  else:
+    result = n
+
+proc impliesGe(fact, x, c: PNode): TImplication =
+  InternalAssert isLocation(x)
+  case fact.sons[0].sym.magic
+  of someEq:
+    if sameTree(fact.sons[1], x):
+      if isValue(fact.sons[2]) and isValue(c):
+        # fact:  x = 4;  question x >= 56? --> true iff 4 >= 56
+        if leValue(c, fact.sons[2]): result = impYes
+        else: result = impNo
+    elif sameTree(fact.sons[2], x):
+      if isValue(fact.sons[1]) and isValue(c):
+        if leValue(c, fact.sons[1]): result = impYes
+        else: result = impNo
+  of someLt:
+    if sameTree(fact.sons[1], x):
+      if isValue(fact.sons[2]) and isValue(c):
+        # fact:  x < 4;  question N <= x? --> false iff N <= 4
+        if leValue(fact.sons[2], c): result = impNo
+        # fact:  x < 4;  question 2 <= x? --> we don't know
+    elif sameTree(fact.sons[2], x):
+      # fact: 3 < x; question: N-1 < x ?  --> true iff N-1 <= 3
+      if isValue(fact.sons[1]) and isValue(c):
+        if leValue(c.pred, fact.sons[1]): result = impYes
+  of someLe:
+    if sameTree(fact.sons[1], x):
+      if isValue(fact.sons[2]) and isValue(c):
+        # fact:  x <= 4;  question x >= 56? --> false iff 4 <= 56
+        if leValue(fact.sons[2], c): result = impNo
+        # fact:  x <= 4;  question x >= 2? --> we don't know
+    elif sameTree(fact.sons[2], x):
+      # fact: 3 <= x; question: x >= 2 ?  --> true iff 2 <= 3
+      if isValue(fact.sons[1]) and isValue(c):
+        if leValue(c, fact.sons[1]): result = impYes
+  of mNot, mOr, mAnd: internalError(x.info, "impliesGe")
+  else: nil
+
+proc impliesLe(fact, x, c: PNode): TImplication =
+  if not isLocation(x):
+    return impliesGe(fact, c, x)
+  case fact.sons[0].sym.magic
+  of someEq:
+    if sameTree(fact.sons[1], x):
+      if isValue(fact.sons[2]) and isValue(c):
+        # fact:  x = 4;  question x <= 56? --> true iff 4 <= 56
+        if leValue(fact.sons[2], c): result = impYes
+        else: result = impNo
+    elif sameTree(fact.sons[2], x):
+      if isValue(fact.sons[1]) and isValue(c):
+        if leValue(fact.sons[1], c): result = impYes
+        else: result = impNo
+  of someLt:
+    if sameTree(fact.sons[1], x):
+      if isValue(fact.sons[2]) and isValue(c):
+        # fact:  x < 4;  question x <= N? --> true iff N-1 <= 4
+        if leValue(fact.sons[2], c.pred): result = impYes
+        # fact:  x < 4;  question x <= 2? --> we don't know
+    elif sameTree(fact.sons[2], x):
+      # fact: 3 < x; question: x <= 1 ?  --> false iff 1 <= 3
+      if isValue(fact.sons[1]) and isValue(c): 
+        if leValue(c, fact.sons[1]): result = impNo
+    
+  of someLe:
+    if sameTree(fact.sons[1], x):
+      if isValue(fact.sons[2]) and isValue(c):
+        # fact:  x <= 4;  question x <= 56? --> true iff 4 <= 56
+        if leValue(fact.sons[2], c): result = impYes
+        # fact:  x <= 4;  question x <= 2? --> we don't know
+    
+    elif sameTree(fact.sons[2], x):
+      # fact: 3 <= x; question: x <= 2 ?  --> false iff 2 < 3
+      if isValue(fact.sons[1]) and isValue(c): 
+        if leValue(c, fact.sons[1].pred): result = impNo
+
+  of mNot, mOr, mAnd: internalError(x.info, "impliesLe")
+  else: nil
+
+proc impliesLt(fact, x, c: PNode): TImplication =
+  # x < 3  same as x <= 2:
+  let p = c.pred
+  if p != c:
+    result = impliesLe(fact, x, p)
+  else:
+    # 4 < x  same as 3 <= x
+    let q = x.pred
+    if q != x:
+      result = impliesLe(fact, q, c)
+
+proc factImplies(fact, prop: PNode, isNegation: bool): TImplication =
+  case fact.getMagic
+  of mNot:
+    case factImplies(fact.sons[1], prop, not isNegation)
+    of impUnknown: return impUnknown
+    of impNo: return impYes
+    of impYes: return impNo
+  of mAnd:
+    if not isNegation:
+      result = factImplies(fact.sons[1], prop, isNegation)
+      if result != impUnknown: return result
+      return factImplies(fact.sons[2], prop, isNegation)
+    else:
+      # careful!  not (a and b)  means  not a or not b:
+      # a or b --> both need to imply 'prop'
+      let a = factImplies(fact.sons[1], prop, isNegation)
+      let b = factImplies(fact.sons[2], prop, isNegation)
+      if a == b: return a
+      return impUnknown
+  else: discard
+  
+  case prop.sons[0].sym.magic
+  of mNot:
+    case fact.factImplies(prop.sons[1], isNegation)
+    of impUnknown: result = impUnknown
+    of impNo: result = impYes
+    of impYes: result = impNo
+  of mIsNil:
+    result = impliesIsNil(fact, prop)
+  of someEq:
+    result = impliesEq(fact, prop)
+  of someLe:
+    result = impliesLe(fact, prop.sons[1], prop.sons[2])
+  of someLt:
+    result = impliesLt(fact, prop.sons[1], prop.sons[2])
+  else:
+    internalError(prop.info, "invalid proposition")
+
+proc doesImply*(facts: TModel, prop: PNode): TImplication =
+  assert prop.kind in nkCallKinds
+  for f in facts:
+    result = f.factImplies(prop, false)
+    if result != impUnknown: return
+
+proc impliesNotNil*(facts: TModel, arg: PNode): TImplication =
+  var x = newNodeI(nkCall, arg.info, 2)
+  x.sons[0] = newSymNode(getSysMagic("isNil", mIsNil))
+  x.sons[1] = arg
+  result = doesImply(facts, x.neg)
diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim
index 352b6ca04..1972dec98 100644
--- a/compiler/magicsys.nim
+++ b/compiler/magicsys.nim
@@ -43,6 +43,18 @@ proc getSysSym(name: string): PSym =
     result.typ = newType(tyError, systemModule)
   if result.kind == skStub: loadStub(result)
   
+proc getSysMagic*(name: string, m: TMagic): PSym =
+  var ti: TIdentIter
+  let id = getIdent(name)
+  result = InitIdentIter(ti, systemModule.tab, id)
+  while result != nil:
+    if result.kind == skStub: loadStub(result)
+    if result.magic == m: return result
+    result = NextIdentIter(ti, systemModule.tab)
+  rawMessage(errSystemNeeds, name)
+  result = newSym(skError, id, systemModule, systemModule.info)
+  result.typ = newType(tyError, systemModule)
+  
 proc sysTypeFromName*(name: string): PType = 
   result = getSysSym(name).typ
 
@@ -111,7 +123,9 @@ proc skipIntLit*(t: PType): PType {.inline.} =
 
 proc AddSonSkipIntLit*(father, son: PType) =
   if isNil(father.sons): father.sons = @[]
-  add(father.sons, son.skipIntLit)
+  let s = son.skipIntLit
+  add(father.sons, s)
+  propagateToOwner(father, s)
 
 proc setIntLitType*(result: PNode) =
   let i = result.intVal
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index f75aec0d5..302a7cfd8 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -106,7 +106,7 @@ type
     warnUnknownSubstitutionX, warnLanguageXNotSupported, warnCommentXIgnored, 
     warnNilStatement, warnAnalysisLoophole,
     warnDifferentHeaps, warnWriteToForeignHeap, warnImplicitClosure,
-    warnEachIdentIsTuple, warnShadowIdent, warnUninit, warnUser,
+    warnEachIdentIsTuple, warnShadowIdent, warnProveInit, warnUninit, warnUser,
     hintSuccess, hintSuccessX, 
     hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded, 
     hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled, 
@@ -355,7 +355,8 @@ const
     warnImplicitClosure: "implicit closure convention: '$1' [ImplicitClosure]",
     warnEachIdentIsTuple: "each identifier is a tuple [EachIdentIsTuple]",
     warnShadowIdent: "shadowed identifier: '$1' [ShadowIdent]",
-    warnUninit: "read from potentially uninitialized variable: '$1' [Uninit]",
+    warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future. [ProveInit]",
+    warnUninit: "'$1' might not have been initialized [Uninit]",
     warnUser: "$1 [User]", 
     hintSuccess: "operation successful [Success]", 
     hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]", 
@@ -375,14 +376,14 @@ const
     hintUser: "$1 [User]"]
 
 const
-  WarningsToStr*: array[0..20, string] = ["CannotOpenFile", "OctalEscape", 
+  WarningsToStr*: array[0..21, string] = ["CannotOpenFile", "OctalEscape", 
     "XIsNeverRead", "XmightNotBeenInit",
     "Deprecated", "ConfigDeprecated",
     "SmallLshouldNotBeUsed", "UnknownMagic", 
     "RedefinitionOfLabel", "UnknownSubstitutionX", "LanguageXNotSupported", 
     "CommentXIgnored", "NilStmt",
     "AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap",
-    "ImplicitClosure", "EachIdentIsTuple", "ShadowIdent", "Uninit",
+    "ImplicitClosure", "EachIdentIsTuple", "ShadowIdent", "ProveInit", "Uninit",
     "User"]
 
   HintsToStr*: array[0..15, string] = ["Success", "SuccessX", "LineTooLong", 
diff --git a/compiler/nimrod.ini b/compiler/nimrod.ini
index bc2f775b6..49dcd25ba 100644
--- a/compiler/nimrod.ini
+++ b/compiler/nimrod.ini
@@ -64,7 +64,6 @@ Files: "bin/empty.txt"
 
 [Lib]
 Files: "lib/nimbase.h"
-Files: "lib/copying.txt"
 Files: "lib/*.nim"
 Files: "lib/*.cfg"
 
diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim
index de7bcaeee..283f83906 100644
--- a/compiler/parampatterns.nim
+++ b/compiler/parampatterns.nim
@@ -50,6 +50,8 @@ proc add(code: var TPatternCode, op: TOpcode) {.inline.} =
 proc whichAlias*(p: PSym): TAliasRequest =
   if p.constraint != nil:
     result = TAliasRequest(p.constraint.strVal[0].ord)
+  else:
+    result = aqNone
 
 proc compileConstraints(p: PNode, result: var TPatternCode) =
   case p.kind
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index cc432aea8..cecec8e5e 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -50,7 +50,7 @@ const
   typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl, 
     wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern, wShallow, 
     wImportcpp, wImportobjc, wError, wIncompleteStruct, wByCopy, wByRef,
-    wInheritable, wGenSym, wInject}
+    wInheritable, wGenSym, wInject, wRequiresInit}
   fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern, 
     wImportcpp, wImportobjc, wError}
   varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, 
@@ -253,11 +253,11 @@ proc processNote(c: PContext, n: PNode) =
     of wHint:
       var x = findStr(msgs.HintsToStr, n.sons[0].sons[1].ident.s)
       if x >= 0: nk = TNoteKind(x + ord(hintMin))
-      else: invalidPragma(n)
+      else: invalidPragma(n); return
     of wWarning:
       var x = findStr(msgs.WarningsToStr, n.sons[0].sons[1].ident.s)
       if x >= 0: nk = TNoteKind(x + ord(warnMin))
-      else: InvalidPragma(n)
+      else: InvalidPragma(n); return
     else:
       invalidPragma(n)
       return
@@ -695,6 +695,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
           noVal(it)
           if sym.typ == nil: invalidPragma(it)
           else: incl(sym.typ.flags, tfIncompleteStruct)
+        of wRequiresInit:
+          noVal(it)
+          if sym.typ == nil: invalidPragma(it)
+          else: incl(sym.typ.flags, tfNeedsInit)
         of wByRef:
           noVal(it)
           if sym == nil or sym.typ == nil:
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index fba028a46..cdab9b535 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1601,6 +1601,25 @@ proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
     addSonSkipIntLit(typ, n.sons[i].typ)
   result.typ = typ
 
+proc checkInitialized(n: PNode, ids: TIntSet, info: TLineInfo) =
+  case n.kind
+  of nkRecList:
+    for i in countup(0, sonsLen(n) - 1):
+      checkInitialized(n.sons[i], ids, info)
+  of nkRecCase:
+    if (n.sons[0].kind != nkSym): InternalError(info, "checkInitialized")
+    checkInitialized(n.sons[0], ids, info)
+    when false:
+      # XXX we cannot check here, as we don't know the branch!
+      for i in countup(1, sonsLen(n) - 1):
+        case n.sons[i].kind
+        of nkOfBranch, nkElse: checkInitialized(lastSon(n.sons[i]), ids, info)
+        else: internalError(info, "checkInitialized")
+  of nkSym:
+    if tfNeedsInit in n.sym.typ.flags and n.sym.name.id notin ids:
+      Message(info, errGenerated, "field not initialized: " & n.sym.name.s)
+  else: internalError(info, "checkInitialized")
+
 proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
   var t = semTypeNode(c, n.sons[0], nil)
   result = n
@@ -1611,6 +1630,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
   if t.kind != tyObject:
     localError(n.info, errGenerated, "object constructor needs an object type")
     return
+  var objType = t
   var ids = initIntSet()
   for i in 1.. <n.len:
     let it = n.sons[i]
@@ -1642,6 +1662,11 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
       localError(it.info, errUndeclaredFieldX, id.s)
     it.sons[1] = e
     # XXX object field name check for 'case objects' if the kind is static?
+  if tfNeedsInit in objType.flags:
+    while true:
+      checkInitialized(objType.n, ids, n.info)
+      if objType.sons[0] == nil: break
+      objType = skipTypes(objType.sons[0], {tyGenericInst})
 
 proc semBlock(c: PContext, n: PNode): PNode =
   result = n
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index 64aae09c1..151cb9cbc 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -9,7 +9,7 @@
 
 import
   intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, 
-  wordrecg, strutils, options
+  wordrecg, strutils, options, guards
 
 # Second semantic checking pass over the AST. Necessary because the old
 # way had some inherent problems. Performs:
@@ -75,7 +75,7 @@ type
     owner: PSym
     init: seq[int] # list of initialized variables
                    # coming soon: "guard" tracking for 'let' variables
-  
+    guards: TModel # nested guards
   PEffects = var TEffects
 
 proc isLocalVar(a: PEffects, s: PSym): bool =
@@ -93,11 +93,14 @@ proc useVar(a: PEffects, n: PNode) =
   let s = n.sym
   if isLocalVar(a, s):
     if s.id notin a.init:
-      if true:
-        Message(n.info, warnUninit, s.name.s)
+      if tfNeedsInit in s.typ.flags:
+        when true:
+          Message(n.info, warnProveInit, s.name.s)
+        else:
+          Message(n.info, errGenerated,
+            "'$1' might not have been initialized" % s.name.s)
       else:
-        Message(n.info, errGenerated,
-          "read from potentially uninitialized variable: '$1'" % s.name.s)
+        Message(n.info, warnUninit, s.name.s)
       # prevent superfluous warnings about the same variable:
       a.init.add s.id
 
@@ -295,7 +298,7 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
   let tagSpec = effectSpec(pragma, wTags)
   mergeTags(tracked, tagSpec, n)
 
-proc trackOperand(tracked: PEffects, n: PNode) =
+proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
   let op = n.typ
   if op != nil and op.kind == tyProc and n.kind != nkNilLit:
     InternalAssert op.n.sons[0].kind == nkEffectList
@@ -312,16 +315,40 @@ proc trackOperand(tracked: PEffects, n: PNode) =
     else:
       mergeEffects(tracked, effectList.sons[exceptionEffects], n)
       mergeTags(tracked, effectList.sons[tagEffects], n)
+  if paramType != nil and tfNotNil in paramType.flags and
+      op != nil and tfNotNil notin op.flags:
+    case impliesNotNil(tracked.guards, n)
+    of impUnknown:
+      Message(n.info, errGenerated, 
+              "cannot prove '$1' is not nil" % n.renderTree)
+    of impNo:
+      Message(n.info, errGenerated, "'$1' is provably nil" % n.renderTree)
+    of impYes: discard
+
+proc breaksBlock(n: PNode): bool =
+  case n.kind
+  of nkStmtList, nkStmtListExpr:
+    for c in n: 
+      if breaksBlock(c): return true
+  of nkBreakStmt, nkReturnStmt, nkRaiseStmt:
+    return true
+  of nkCallKinds:
+    if n.sons[0].kind == nkSym and sfNoReturn in n.sons[0].sym.flags:
+      return true
+  else:
+    discard
 
 proc trackCase(tracked: PEffects, n: PNode) =
   track(tracked, n.sons[0])
   let oldState = tracked.init.len
   var inter: TIntersection = @[]
+  var toCover = 0
   for i in 1.. <n.len:
     let branch = n.sons[i]
     setLen(tracked.init, oldState)
     for i in 0 .. <branch.len:
       track(tracked, branch.sons[i])
+    if not breaksBlock(branch.lastSon): inc toCover
     for i in oldState.. <tracked.init.len:
       addToIntersection(inter, tracked.init[i])
   let exh = case skipTypes(n.sons[0].Typ, abstractVarRange-{tyTypeDesc}).Kind
@@ -332,30 +359,41 @@ proc trackCase(tracked: PEffects, n: PNode) =
   setLen(tracked.init, oldState)
   if exh:
     for id, count in items(inter):
-      if count == n.len-1: tracked.init.add id
+      if count >= toCover: tracked.init.add id
     # else we can't merge
 
 proc trackIf(tracked: PEffects, n: PNode) =
   track(tracked, n.sons[0].sons[0])
+  let oldFacts = tracked.guards.len
+  addFact(tracked.guards, n.sons[0].sons[0])
   let oldState = tracked.init.len
 
   var inter: TIntersection = @[]
+  var toCover = 0
   track(tracked, n.sons[0].sons[1])
+  if not breaksBlock(n.sons[0].sons[1]): inc toCover
   for i in oldState.. <tracked.init.len:
     addToIntersection(inter, tracked.init[i])
 
   for i in 1.. <n.len:
     let branch = n.sons[i]
+    setLen(tracked.guards, oldFacts)
+    for j in 0..i-1:
+      addFactNeg(tracked.guards, n.sons[j].sons[0])
+    if branch.len > 1:
+      addFact(tracked.guards, branch.sons[0])
     setLen(tracked.init, oldState)
     for i in 0 .. <branch.len:
       track(tracked, branch.sons[i])
+    if not breaksBlock(branch.lastSon): inc toCover
     for i in oldState.. <tracked.init.len:
       addToIntersection(inter, tracked.init[i])
   setLen(tracked.init, oldState)
   if lastSon(n).len == 1:
     for id, count in items(inter):
-      if count == n.len: tracked.init.add id
+      if count >= toCover: tracked.init.add id
     # else we can't merge as it is not exhaustive
+  setLen(tracked.guards, oldFacts)
   
 proc trackBlock(tracked: PEffects, n: PNode) =
   if n.kind in {nkStmtList, nkStmtListExpr}:
@@ -377,6 +415,9 @@ proc isTrue(n: PNode): bool =
   n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
     n.kind == nkIntLit and n.intVal != 0
 
+proc paramType(op: PType, i: int): PType =
+  if op != nil and i < op.len: result = op.sons[i]
+
 proc track(tracked: PEffects, n: PNode) =
   case n.kind
   of nkSym:
@@ -404,11 +445,12 @@ proc track(tracked: PEffects, n: PNode) =
       else:
         mergeEffects(tracked, effectList.sons[exceptionEffects], n)
         mergeTags(tracked, effectList.sons[tagEffects], n)
-    for i in 1 .. <len(n): trackOperand(tracked, n.sons[i])
+    for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i))
     if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, 
                                            mNewSeq, mShallowCopy}:
       # may not look like an assignment, but it is:
       initVar(tracked, n.sons[1])
+      # XXX new(objWithNotNil) is not initialized properly!
     for i in 0 .. <safeLen(n):
       track(tracked, n.sons[i])
   of nkTryStmt: trackTryStmt(tracked, n)
@@ -510,8 +552,14 @@ proc trackProc*(s: PSym, body: PNode) =
   t.tags = effects.sons[tagEffects]
   t.owner = s
   t.init = @[]
+  t.guards = @[]
   track(t, body)
   
+  if not isEmptyType(s.typ.sons[0]) and tfNeedsInit in s.typ.sons[0].flags and
+      s.kind in {skProc, skConverter, skMethod}:
+    var res = s.ast.sons[resultPos].sym # get result symbol
+    if res.id notin t.init:
+      Message(body.info, warnProveInit, "result")
   let p = s.ast.sons[pragmasPos]
   let raisesSpec = effectSpec(p, wRaises)
   if not isNil(raisesSpec):
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 6123957cd..75ab9920d 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -374,7 +374,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
             if warnShadowIdent in gNotes and not identWithin(def, v.name):
               Message(a.info, warnShadowIdent, v.name.s)
       if def != nil and def.kind != nkEmpty:
-        # this is only needed for the evaluation pass:
+        # this is needed for the evaluation pass and for the guard checking:
         v.ast = def
         if sfThread in v.flags: LocalError(def.info, errThreadvarCannotInit)
       if a.kind != nkVarTuple:
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 658b3507f..769e2ab7d 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -23,7 +23,7 @@ proc newConstraint(c: PContext, k: TTypeKind): PType =
 
 proc semEnum(c: PContext, n: PNode, prev: PType): PType =
   if n.sonsLen == 0: return newConstraint(c, tyEnum)
-  var 
+  var
     counter, x: BiggestInt
     e: PSym
     base: PType
@@ -39,6 +39,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
     counter = lastOrd(base) + 1
   rawAddSon(result, base)
   let isPure = result.sym != nil and sfPure in result.sym.flags
+  var hasNull = false
   for i in countup(1, sonsLen(n) - 1): 
     case n.sons[i].kind
     of nkEnumFieldDef: 
@@ -74,6 +75,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
     else: illFormedAst(n)
     e.typ = result
     e.position = int(counter)
+    if e.position == 0: hasNull = true
     if result.sym != nil and sfExported in result.sym.flags:
       incl(e.flags, sfUsed)
       incl(e.flags, sfExported)
@@ -81,6 +83,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
     addSon(result.n, newSymNode(e))
     if sfGenSym notin e.flags and not isPure: addDecl(c, e)
     inc(counter)
+  if not hasNull: incl(result.flags, tfNeedsInit)
 
 proc semSet(c: PContext, n: PNode, prev: PType): PType = 
   result = newOrPrevType(tySet, prev, c)
@@ -168,7 +171,14 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
 proc semRange(c: PContext, n: PNode, prev: PType): PType =
   result = nil
   if sonsLen(n) == 2:
-    if isRange(n[1]): result = semRangeAux(c, n[1], prev)
+    if isRange(n[1]):
+      result = semRangeAux(c, n[1], prev)
+      let n = result.n
+      if n.sons[0].kind in {nkCharLit..nkUInt64Lit}:
+        if n.sons[0].intVal > 0 or n.sons[1].intVal < 0:
+          incl(result.flags, tfNeedsInit)
+      elif n.sons[0].floatVal > 0.0 or n.sons[1].floatVal < 0.0:
+        incl(result.flags, tfNeedsInit)
     else:
       LocalError(n.sons[0].info, errRangeExpected)
       result = newOrPrevType(tyError, prev, c)
@@ -386,34 +396,34 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
           swap(branch.sons[L-2], branch.sons[L-1])
     checkForOverlap(c, t, i, branchIndex)
     
-proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int, 
-                      father: PNode, rectype: PSym)
-proc semRecordCase(c: PContext, n: PNode, check: var TIntSet, pos: var int, 
-                   father: PNode, rectype: PSym) = 
+proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
+                      father: PNode, rectype: PType)
+proc semRecordCase(c: PContext, n: PNode, check: var TIntSet, pos: var int,
+                   father: PNode, rectype: PType) =
   var a = copyNode(n)
   checkMinSonsLen(n, 2)
   semRecordNodeAux(c, n.sons[0], check, pos, a, rectype)
-  if a.sons[0].kind != nkSym: 
+  if a.sons[0].kind != nkSym:
     internalError("semRecordCase: discriminant is no symbol")
     return
   incl(a.sons[0].sym.flags, sfDiscriminant)
   var covered: biggestInt = 0
   var typ = skipTypes(a.sons[0].Typ, abstractVar-{tyTypeDesc})
-  if not isOrdinalType(typ): 
+  if not isOrdinalType(typ):
     LocalError(n.info, errSelectorMustBeOrdinal)
-  elif firstOrd(typ) < 0: 
+  elif firstOrd(typ) < 0:
     LocalError(n.info, errOrdXMustNotBeNegative, a.sons[0].sym.name.s)
-  elif lengthOrd(typ) > 0x00007FFF: 
+  elif lengthOrd(typ) > 0x00007FFF:
     LocalError(n.info, errLenXinvalid, a.sons[0].sym.name.s)
   var chckCovered = true
-  for i in countup(1, sonsLen(n) - 1): 
+  for i in countup(1, sonsLen(n) - 1):
     var b = copyTree(n.sons[i])
     addSon(a, b)
     case n.sons[i].kind
-    of nkOfBranch: 
+    of nkOfBranch:
       checkMinSonsLen(b, 2)
       semCaseBranch(c, a, b, i, covered)
-    of nkElse: 
+    of nkElse:
       chckCovered = false
       checkSonsLen(b, 1)
     else: illFormedAst(n)
@@ -424,7 +434,7 @@ proc semRecordCase(c: PContext, n: PNode, check: var TIntSet, pos: var int,
   addSon(father, a)
 
 proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int, 
-                      father: PNode, rectype: PSym) = 
+                      father: PNode, rectype: PType) =
   if n == nil: return
   case n.kind
   of nkRecWhen:
@@ -463,7 +473,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
     semRecordCase(c, n, check, pos, father, rectype)
   of nkNilLit: 
     if father.kind != nkRecList: addSon(father, newNodeI(nkRecList, n.info))
-  of nkRecList: 
+  of nkRecList:
     # attempt to keep the nesting at a sane level:
     var a = if father.kind == nkRecList: father else: copyNode(n)
     for i in countup(0, sonsLen(n) - 1): 
@@ -473,7 +483,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
     checkMinSonsLen(n, 3)
     var length = sonsLen(n)
     var a: PNode
-    if father.kind != nkRecList and length >= 4: a = newNodeI(nkRecList, n.info)
+    if father.kind != nkRecList and length>=4: a = newNodeI(nkRecList, n.info)
     else: a = ast.emptyNode
     if n.sons[length-1].kind != nkEmpty: 
       localError(n.sons[length-1].info, errInitHereNotAllowed)
@@ -483,17 +493,19 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
       typ = errorType(c)
     else:
       typ = semTypeNode(c, n.sons[length-2], nil)
+      propagateToOwner(rectype, typ)
+    let rec = rectype.sym
     for i in countup(0, sonsLen(n)-3):
       var f = semIdentWithPragma(c, skField, n.sons[i], {sfExported})
       suggestSym(n.sons[i], f)
       f.typ = typ
       f.position = pos
-      if (rectype != nil) and ({sfImportc, sfExportc} * rectype.flags != {}) and
+      if (rec != nil) and ({sfImportc, sfExportc} * rec.flags != {}) and
           (f.loc.r == nil): 
         f.loc.r = toRope(f.name.s)
-        f.flags = f.flags + ({sfImportc, sfExportc} * rectype.flags)
+        f.flags = f.flags + ({sfImportc, sfExportc} * rec.flags)
       inc(pos)
-      if ContainsOrIncl(check, f.name.id): 
+      if ContainsOrIncl(check, f.name.id):
         localError(n.sons[i].info, errAttemptToRedefine, f.name.s)
       if a.kind == nkEmpty: addSon(father, newSymNode(f))
       else: addSon(a, newSymNode(f))
@@ -502,20 +514,20 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
   else: illFormedAst(n)
   
 proc addInheritedFieldsAux(c: PContext, check: var TIntSet, pos: var int, 
-                           n: PNode) = 
+                           n: PNode) =
   case n.kind
-  of nkRecCase: 
+  of nkRecCase:
     if (n.sons[0].kind != nkSym): InternalError(n.info, "addInheritedFieldsAux")
     addInheritedFieldsAux(c, check, pos, n.sons[0])
-    for i in countup(1, sonsLen(n) - 1): 
+    for i in countup(1, sonsLen(n) - 1):
       case n.sons[i].kind
-      of nkOfBranch, nkElse: 
+      of nkOfBranch, nkElse:
         addInheritedFieldsAux(c, check, pos, lastSon(n.sons[i]))
       else: internalError(n.info, "addInheritedFieldsAux(record case branch)")
-  of nkRecList: 
-    for i in countup(0, sonsLen(n) - 1): 
+  of nkRecList:
+    for i in countup(0, sonsLen(n) - 1):
       addInheritedFieldsAux(c, check, pos, n.sons[i])
-  of nkSym: 
+  of nkSym:
     Incl(check, n.sym.name.id)
     inc(pos)
   else: InternalError(n.info, "addInheritedFieldsAux()")
@@ -553,7 +565,7 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
   result = newOrPrevType(tyObject, prev, c)
   rawAddSon(result, base)
   result.n = newNodeI(nkRecList, n.info)
-  semRecordNodeAux(c, n.sons[2], check, pos, result.n, result.sym)
+  semRecordNodeAux(c, n.sons[2], check, pos, result.n, result)
   if n.sons[0].kind != nkEmpty:
     # dummy symbol for `pragma`:
     var s = newSymS(skType, newIdentNode(getIdent("dummy"), n.info), c)
@@ -853,6 +865,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
         if result.kind in NilableTypes and n.sons[2].kind == nkNilLit:
           result = freshType(result, prev)
           result.flags.incl(tfNotNil)
+          result.flags.incl(tfNeedsInit)
         else:
           LocalError(n.info, errGenerated, "invalid type")
       else:
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 26341525c..31fbc33e1 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -152,6 +152,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
       x = lookupTypeVar(cl, x)
       if header == nil: header = copyType(t, t.owner, false)
       header.sons[i] = x
+      propagateToOwner(header, x)
       #idTablePut(cl.typeMap, body.sons[i-1], x)
   if header != nil:
     # search again after first pass:
@@ -170,6 +171,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
     var x = replaceTypeVarsT(cl, t.sons[i])
     assert x.kind != tyGenericInvokation
     header.sons[i] = x
+    propagateToOwner(header, x)
     idTablePut(cl.typeMap, body.sons[i-1], x)
   
   for i in countup(1, sonsLen(t) - 1): 
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 058143cdd..a35669e1d 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -504,8 +504,8 @@ proc transformCase(c: PTransf, n: PNode): PTransNode =
     result.add(elseBranch)
   elif result.Pnode.lastSon.kind != nkElse and not (
       skipTypes(n.sons[0].Typ, abstractVarRange).Kind in
-        {tyInt..tyInt64, tyChar, tyEnum}):
-    # fix a stupid code gen bug by normalizing: 
+        {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32}):
+    # fix a stupid code gen bug by normalizing:
     var elseBranch = newTransNode(nkElse, n.info, 1)
     elseBranch[0] = newTransNode(nkNilLit, n.info, 0)
     add(result, elseBranch)
@@ -704,7 +704,7 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
   if nfTransf in n.flags or prc.kind in {skTemplate, skMacro}:
     result = n
   else:
-    when useEffectSystem: trackProc(prc, n)
+    #when useEffectSystem: trackProc(prc, n)
     var c = openTransf(module, "")
     result = processTransf(c, n)
     if prc.kind != skMacro:
@@ -713,6 +713,7 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
     if prc.kind == skIterator and prc.typ.callConv == ccClosure:
       result = lambdalifting.liftIterator(prc, result)
     incl(result.flags, nfTransf)
+    when useEffectSystem: trackProc(prc, result)
 
 proc transformStmt*(module: PSym, n: PNode): PNode =
   if nfTransf in n.flags:
diff --git a/compiler/trees.nim b/compiler/trees.nim
index f371cb021..ab5c97a19 100644
--- a/compiler/trees.nim
+++ b/compiler/trees.nim
@@ -93,8 +93,7 @@ proc getOpSym*(op: PNode): PSym =
   
 proc getMagic*(op: PNode): TMagic = 
   case op.kind
-  of nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit, nkPrefix, nkPostfix,
-     nkInfix: 
+  of nkCallKinds:
     case op.sons[0].Kind
     of nkSym: result = op.sons[0].sym.magic
     else: result = mNone
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index 36d08c718..2a8a02bd6 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -41,7 +41,7 @@ type
     
     wImmediate, wDestructor, wImportCpp, wImportObjC,
     wImportCompilerProc,
-    wImportc, wExportc, wIncompleteStruct,
+    wImportc, wExportc, wIncompleteStruct, wRequiresInit,
     wAlign, wNodecl, wPure, wSideeffect, wHeader,
     wNosideeffect, wNoreturn, wMerge, wLib, wDynlib, wCompilerproc, wProcVar, 
     wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef, 
@@ -122,7 +122,7 @@ const
     
     "immediate", "destructor", "importcpp", "importobjc",
     "importcompilerproc", "importc", "exportc", "incompletestruct",
-    "align", "nodecl", "pure", "sideeffect",
+    "requiresinit", "align", "nodecl", "pure", "sideeffect",
     "header", "nosideeffect", "noreturn", "merge", "lib", "dynlib", 
     "compilerproc", "procvar", "fatal", "error", "warning", "hint", "line", 
     "push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace",