summary refs log tree commit diff stats
diff options
context:
space:
mode:
-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
-rw-r--r--doc/advopt.txt2
-rw-r--r--doc/lib.txt16
-rw-r--r--doc/manual.txt80
-rw-r--r--doc/nimrodc.txt2
-rw-r--r--doc/tut1.txt15
-rw-r--r--lib/copying.txt24
-rw-r--r--lib/packages/docutils/rst.nim2
-rw-r--r--lib/packages/docutils/rstast.nim2
-rw-r--r--lib/packages/docutils/rstgen.nim4
-rw-r--r--lib/pure/pegs.nim2
-rw-r--r--lib/pure/times.nim36
-rw-r--r--lib/wrappers/readline/readline.nim47
-rw-r--r--tests/reject/tdisallowif.nim2
-rw-r--r--tests/reject/tnotnil1.nim24
-rw-r--r--tests/reject/tnotnil2.nim24
-rw-r--r--tests/reject/tuninit1.nim36
-rw-r--r--tests/run/tpegs.nim2
-rw-r--r--todo.txt3
-rw-r--r--tools/niminst/debcreation.nim4
-rw-r--r--web/index.txt2
-rw-r--r--web/news.txt4
-rw-r--r--web/nimrod.ini4
37 files changed, 759 insertions, 169 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", 
diff --git a/doc/advopt.txt b/doc/advopt.txt
index 38461244d..3b6fafd0f 100644
--- a/doc/advopt.txt
+++ b/doc/advopt.txt
@@ -12,6 +12,8 @@ Advanced commands:
   //check                   checks the project for syntax and semantic
   //idetools                compiler support for IDEs: possible options:
     --track:FILE,LINE,COL   track a file/cursor position
+    --trackDirty:DIRTY_FILE,ORIG_FILE,LINE,COL
+                            track a file, currently not saved to disk
     --suggest               suggest all possible symbols at position
     --def                   list all possible definitions at position
     --context               list possible invokation context
diff --git a/doc/lib.txt b/doc/lib.txt
index 2f781f375..1b004aa9d 100644
--- a/doc/lib.txt
+++ b/doc/lib.txt
@@ -255,6 +255,22 @@ Parsers
   This is a low level module that implements an extremely efficient buffering
   scheme for lexers and parsers. This is used by the diverse parsing modules.
 
+* `highlite <highlite.html>`_
+  Source highlighter for programming or markup languages.  Currently
+  only few languages are supported, other languages may be added.
+  The interface supports one language nested in another.
+
+* `rst <rst.html>`_
+  This module implements a reStructuredText parser. A large subset
+  is implemented. Some features of the markdown wiki syntax are
+  also supported.
+
+* `rstast <rstast.html>`_
+  This module implements an AST for the reStructuredText parser.
+
+* `rstgen <rstgen.html>`_
+  This module implements a generator of HTML/Latex from reStructuredText.
+
 
 XML Processing
 --------------
diff --git a/doc/manual.txt b/doc/manual.txt
index f163e0d5f..2c19911b4 100644
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -327,36 +327,36 @@ Numerical constants
 
 `Numerical constants`:idx: are of a single type and have the form::
 
-  hexdigit ::= digit | 'A'..'F' | 'a'..'f'
-  octdigit ::= '0'..'7'
-  bindigit ::= '0'..'1'
-  HEX_LIT ::= '0' ('x' | 'X' ) hexdigit ( ['_'] hexdigit )*
-  DEC_LIT ::= digit ( ['_'] digit )*
-  OCT_LIT ::= '0o' octdigit ( ['_'] octdigit )*
-  BIN_LIT ::= '0' ('b' | 'B' ) bindigit ( ['_'] bindigit )*
+  hexdigit = digit | 'A'..'F' | 'a'..'f'
+  octdigit = '0'..'7'
+  bindigit = '0'..'1'
+  HEX_LIT = '0' ('x' | 'X' ) hexdigit ( ['_'] hexdigit )*
+  DEC_LIT = digit ( ['_'] digit )*
+  OCT_LIT = '0o' octdigit ( ['_'] octdigit )*
+  BIN_LIT = '0' ('b' | 'B' ) bindigit ( ['_'] bindigit )*
   
-  INT_LIT ::= HEX_LIT
-            | DEC_LIT
-            | OCT_LIT
-            | BIN_LIT
-
-  INT8_LIT ::= INT_LIT ['\''] ('i' | 'I') '8'
-  INT16_LIT ::= INT_LIT ['\''] ('i' | 'I') '16'
-  INT32_LIT ::= INT_LIT ['\''] ('i' | 'I') '32'
-  INT64_LIT ::= INT_LIT ['\''] ('i' | 'I') '64'
-
-  UINT8_LIT ::= INT_LIT ['\''] ('u' | 'U')
-  UINT8_LIT ::= INT_LIT ['\''] ('u' | 'U') '8'
-  UINT16_LIT ::= INT_LIT ['\''] ('u' | 'U') '16'
-  UINT32_LIT ::= INT_LIT ['\''] ('u' | 'U') '32'
-  UINT64_LIT ::= INT_LIT ['\''] ('u' | 'U') '64'
-
-  exponent ::= ('e' | 'E' ) ['+' | '-'] digit ( ['_'] digit )*
-  FLOAT_LIT ::= digit (['_'] digit)*  ('.' (['_'] digit)* [exponent] |exponent)
-  FLOAT32_LIT ::= HEX_LIT '\'' ('f'|'F') '32'
-             | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] ('f'|'F') '32'
-  FLOAT64_LIT ::= HEX_LIT '\'' ('f'|'F') '64'
-             | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] ('f'|'F') '64'
+  INT_LIT = HEX_LIT
+          | DEC_LIT
+          | OCT_LIT
+          | BIN_LIT
+
+  INT8_LIT = INT_LIT ['\''] ('i' | 'I') '8'
+  INT16_LIT = INT_LIT ['\''] ('i' | 'I') '16'
+  INT32_LIT = INT_LIT ['\''] ('i' | 'I') '32'
+  INT64_LIT = INT_LIT ['\''] ('i' | 'I') '64'
+
+  UINT8_LIT = INT_LIT ['\''] ('u' | 'U')
+  UINT8_LIT = INT_LIT ['\''] ('u' | 'U') '8'
+  UINT16_LIT = INT_LIT ['\''] ('u' | 'U') '16'
+  UINT32_LIT = INT_LIT ['\''] ('u' | 'U') '32'
+  UINT64_LIT = INT_LIT ['\''] ('u' | 'U') '64'
+
+  exponent = ('e' | 'E' ) ['+' | '-'] digit ( ['_'] digit )*
+  FLOAT_LIT = digit (['_'] digit)*  ('.' (['_'] digit)* [exponent] |exponent)
+  FLOAT32_LIT = HEX_LIT '\'' ('f'|'F') '32'
+              | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] ('f'|'F') '32'
+  FLOAT64_LIT = HEX_LIT '\'' ('f'|'F') '64'
+              | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] ('f'|'F') '64'
 
 
 As can be seen in the productions, numerical constants can contain underscores
@@ -1388,7 +1388,7 @@ accesses its environment. If it does so, it has the calling convention
 Distinct type
 -------------
 
-A distinct type is new type derived from a `base type`:idx: that is
+A `distinct type`:idx: is new type derived from a `base type`:idx: that is
 incompatible with its base type. In particular, it is an essential property
 of a distinct type that it **does not** imply a subtype relation between it
 and its base type. Explicit type conversions from a distinct type to its
@@ -1435,7 +1435,7 @@ number without unit; and the same holds for division:
 This quickly gets tedious. The implementations are trivial and the compiler
 should not generate all this code only to optimize it away later - after all
 ``+`` for dollars should produce the same binary code as ``+`` for ints.
-The pragma ``borrow`` has been designed to solve this problem; in principle
+The pragma `borrow`:idx: has been designed to solve this problem; in principle
 it generates the above trivial implementations:
 
 .. code-block:: nimrod
@@ -1818,6 +1818,24 @@ If a proc is annotated with the ``noinit`` pragma this refers to its implicit
   proc returnUndefinedValue: int {.noinit.} = nil
 
 
+The implicit initialization can be also prevented by the `requiresInit`:idx:
+type pragma. The compiler requires an explicit initialization then. However
+it does a `control flow analysis`:idx: to prove the variable has been 
+initialized and does not rely on syntactic properties:
+
+.. code-block:: nimrod
+  type
+    TMyObject = object {.requiresInit.}
+    
+  proc p() =
+    # the following is valid:
+    var x: TMyObject
+    if someCondition():
+      x = a()
+    else:
+      x = a()
+    use x
+
 let statement
 -------------
 
diff --git a/doc/nimrodc.txt b/doc/nimrodc.txt
index 7f77a50d2..339cee382 100644
--- a/doc/nimrodc.txt
+++ b/doc/nimrodc.txt
@@ -20,7 +20,7 @@ on the different supported platforms. It is not a definition of the Nimrod
 programming language (therefore is the `manual <manual.html>`_).

 

 Nimrod is free software; it is licensed under the

-`GNU General Public License <gpl.html>`_.

+`MIT License <http://www.opensource.org/licenses/mit-license.php>`_.

 

 

 Compiler Usage

diff --git a/doc/tut1.txt b/doc/tut1.txt
index 28e23b0f0..0cc9b05c1 100644
--- a/doc/tut1.txt
+++ b/doc/tut1.txt
@@ -1182,6 +1182,21 @@ type and instead write it embedded directly as the type of the first dimension:
   type
     TLightTower = array[1..10, array[north..west, TBlinkLights]]
 
+It is quite frequent to have arrays start at zero, so there's a shortcut syntax
+to specify a range from zero to the specified index minus one:
+
+.. code-block:: nimrod
+  type
+    TIntArray = array[0..5, int] # an array that is indexed with 0..5
+    TQuickArray = array[6, int]  # an array that is indexed with 0..5
+  var
+    x: TIntArray
+    y: TQuickArray
+  x = [1, 2, 3, 4, 5, 6]
+  y = x
+  for i in low(x)..high(x):
+    echo(x[i], y[i])
+
 
 Sequences
 ---------
diff --git a/lib/copying.txt b/lib/copying.txt
deleted file mode 100644
index 0ff6b7d87..000000000
--- a/lib/copying.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-===============================================================================
-Nimrod -- a Compiler for Nimrod. http://nimrod-code.org/
- 
-Copyright (C) 2004-2013 Andreas Rumpf. All rights reserved.
- 
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
- 
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
- 
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
-[ MIT license: http://www.opensource.org/licenses/mit-license.php ]
\ No newline at end of file
diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim
index 54c17367f..91664cd50 100644
--- a/lib/packages/docutils/rst.nim
+++ b/lib/packages/docutils/rst.nim
@@ -7,7 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-## This module implements a `reStructuredText`:idx parser. A large
+## This module implements a `reStructuredText`:idx: parser. A large
 ## subset is implemented. Some features of the `markdown`:idx: wiki syntax are
 ## also supported.
 
diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim
index 23233fd39..3d191dacb 100644
--- a/lib/packages/docutils/rstast.nim
+++ b/lib/packages/docutils/rstast.nim
@@ -7,7 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-## This module implements an AST for the `reStructuredText`:idx parser.
+## This module implements an AST for the `reStructuredText`:idx: parser.
 
 import strutils
 
diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim
index 53bd8188e..a393943fb 100644
--- a/lib/packages/docutils/rstgen.nim
+++ b/lib/packages/docutils/rstgen.nim
@@ -7,7 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-## This module implements a generator of HTML/Latex from `reStructuredText`:idx.
+## This module implements a generator of HTML/Latex from `reStructuredText`:idx:.
 
 import strutils, os, hashes, strtabs, rstast, rst, highlite
 
@@ -692,4 +692,4 @@ proc rstToHtml*(s: string, options: TRstParseOptions,
   var rst = rstParse(s, filen, 0, 1, dummyHasToc, options)
   result = ""
   renderRstToOut(d, rst, result)
-  
\ No newline at end of file
+  
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index b6877696c..d8fed845a 100644
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -82,7 +82,7 @@ type
     of pkChar, pkGreedyRepChar: ch: char
     of pkCharChoice, pkGreedyRepSet: charChoice: ref set[char]
     of pkNonTerminal: nt: PNonTerminal
-    of pkBackRef..pkBackRefIgnoreStyle: index: range[1..MaxSubpatterns]
+    of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns]
     else: sons: seq[TNode]
   PNonTerminal* = ref TNonTerminal
   
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 2eb8d692b..86609c8e3 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -338,24 +338,24 @@ when not defined(JS):
     const
       weekDays: array [0..6, TWeekDay] = [
         dSun, dMon, dTue, dWed, dThu, dFri, dSat]
-    result.second = int(tm.second)
-    result.minute = int(tm.minute)
-    result.hour = int(tm.hour)
-    result.monthday = int(tm.monthday)
-    result.month = TMonth(tm.month)
-    result.year = tm.year + 1900'i32
-    result.weekday = weekDays[int(tm.weekDay)]
-    result.yearday = int(tm.yearday)
-    result.isDST = tm.isDST > 0
-    if local:
-      if result.isDST:
-        result.tzname = getTzname().DST
-      else:
-        result.tzname = getTzname().nonDST
-    else:
-      result.tzname = "UTC"
-    
-    result.timezone = if local: getTimezone() else: 0
+    TTimeInfo(second: int(tm.second),
+      minute: int(tm.minute),
+      hour: int(tm.hour),
+      monthday: int(tm.monthday),
+      month: TMonth(tm.month),
+      year: tm.year + 1900'i32,
+      weekday: weekDays[int(tm.weekDay)],
+      yearday: int(tm.yearday),
+      isDST: tm.isDST > 0,
+      tzname: if local:
+          if tm.isDST > 0:
+            getTzname().DST
+          else:
+            getTzname().nonDST
+        else:
+          "UTC",
+      timezone: if local: getTimezone() else: 0
+    )
   
   proc timeInfoToTM(t: TTimeInfo): structTM =
     const
diff --git a/lib/wrappers/readline/readline.nim b/lib/wrappers/readline/readline.nim
index d14171c46..1f0dd564f 100644
--- a/lib/wrappers/readline/readline.nim
+++ b/lib/wrappers/readline/readline.nim
@@ -156,33 +156,34 @@ const
 type 
   Thook_func* = proc (a2: cstring): cstring{.cdecl.}
 
-# If non-null, this contains the address of a function that the application
-#   wants called before trying the standard tilde expansions.  The function
-#   is called with the text sans tilde, and returns a malloc()'ed string
-#   which is the expansion, or a NULL pointer if the expansion fails. 
+when not defined(macosx):
+  # If non-null, this contains the address of a function that the application
+  #   wants called before trying the standard tilde expansions.  The function
+  #   is called with the text sans tilde, and returns a malloc()'ed string
+  #   which is the expansion, or a NULL pointer if the expansion fails. 
 
-var expansion_preexpansion_hook*{.importc: "tilde_expansion_preexpansion_hook", 
-                                  dynlib: tildeDll.}: Thook_func
+  var expansion_preexpansion_hook*{.importc: "tilde_expansion_preexpansion_hook", 
+                                    dynlib: tildeDll.}: Thook_func
 
-# If non-null, this contains the address of a function to call if the
-#   standard meaning for expanding a tilde fails.  The function is called
-#   with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
-#   which is the expansion, or a NULL pointer if there is no expansion. 
+  # If non-null, this contains the address of a function to call if the
+  #   standard meaning for expanding a tilde fails.  The function is called
+  #   with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
+  #   which is the expansion, or a NULL pointer if there is no expansion. 
 
-var expansion_failure_hook*{.importc: "tilde_expansion_failure_hook", 
-                             dynlib: tildeDll.}: Thook_func
+  var expansion_failure_hook*{.importc: "tilde_expansion_failure_hook", 
+                               dynlib: tildeDll.}: Thook_func
 
-# When non-null, this is a NULL terminated array of strings which
-#   are duplicates for a tilde prefix.  Bash uses this to expand
-#   `=~' and `:~'. 
+  # When non-null, this is a NULL terminated array of strings which
+  #   are duplicates for a tilde prefix.  Bash uses this to expand
+  #   `=~' and `:~'. 
 
-var additional_prefixes*{.importc: "tilde_additional_prefixes", dynlib: tildeDll.}: cstringArray
+  var additional_prefixes*{.importc: "tilde_additional_prefixes", dynlib: tildeDll.}: cstringArray
 
-# When non-null, this is a NULL terminated array of strings which match
-#   the end of a username, instead of just "/".  Bash sets this to
-#   `:' and `=~'. 
+  # When non-null, this is a NULL terminated array of strings which match
+  #   the end of a username, instead of just "/".  Bash sets this to
+  #   `:' and `=~'. 
 
-var additional_suffixes*{.importc: "tilde_additional_suffixes", dynlib: tildeDll.}: cstringArray
+  var additional_suffixes*{.importc: "tilde_additional_suffixes", dynlib: tildeDll.}: cstringArray
 
 # Return a new string which is the result of tilde expanding STRING. 
 
@@ -229,7 +230,8 @@ type
 
 # The current undo list for RL_LINE_BUFFER. 
 
-var undo_list*{.importc: "rl_undo_list", dynlib: readlineDll.}: ptr TUNDO_LIST
+when not defined(macosx):
+  var undo_list*{.importc: "rl_undo_list", dynlib: readlineDll.}: ptr TUNDO_LIST
 
 # The data structure for mapping textual names to code addresses. 
 
@@ -239,7 +241,8 @@ type
     function*: TCommandFunc
 
 
-var funmap*{.importc: "funmap", dynlib: readlineDll.}: ptr ptr TFUNMAP
+when not defined(macosx):
+  var funmap*{.importc: "funmap", dynlib: readlineDll.}: ptr ptr TFUNMAP
 
 # **************************************************************** 
 #								    
diff --git a/tests/reject/tdisallowif.nim b/tests/reject/tdisallowif.nim
index f7bb7098b..10f54288a 100644
--- a/tests/reject/tdisallowif.nim
+++ b/tests/reject/tdisallowif.nim
@@ -21,7 +21,7 @@ s[0] = substr(s[0], 0, 2)
 
 echo s[0]
 
-if true:
+if s[0] != "hi":
   echo "do it"
   echo "more branches"
 else:
diff --git a/tests/reject/tnotnil1.nim b/tests/reject/tnotnil1.nim
new file mode 100644
index 000000000..3535bbd63
--- /dev/null
+++ b/tests/reject/tnotnil1.nim
@@ -0,0 +1,24 @@
+discard """
+  errormsg: "'y' is provably nil"
+  line:22
+"""
+
+import strutils
+
+
+type
+  TObj = object
+    x, y: int
+
+proc q(x: pointer not nil) =
+  nil
+
+proc p() =
+  var x: pointer
+  let y = x
+  if not y.isNil:
+    q(y)
+  else:
+    q(y)
+
+p()
diff --git a/tests/reject/tnotnil2.nim b/tests/reject/tnotnil2.nim
new file mode 100644
index 000000000..bd6b8b675
--- /dev/null
+++ b/tests/reject/tnotnil2.nim
@@ -0,0 +1,24 @@
+discard """
+  errormsg: "cannot prove 'y' is not nil"
+  line:20
+"""
+
+import strutils
+
+
+type
+  TObj = object
+    x, y: int
+
+proc q(x: pointer not nil) =
+  nil
+
+proc p() =
+  var x: pointer
+  let y = x
+  if not y.isNil or y != x:
+    q(y)
+  else:
+    q(y)
+
+p()
diff --git a/tests/reject/tuninit1.nim b/tests/reject/tuninit1.nim
new file mode 100644
index 000000000..2a994b187
--- /dev/null
+++ b/tests/reject/tuninit1.nim
@@ -0,0 +1,36 @@
+discard """
+  errormsg: "'y' might not have been initialized"
+  line:34
+"""
+
+import strutils
+
+{.warning[Uninit]:on.}
+
+proc p =
+  var x, y, z: int
+  if stdin.readLine == "true":
+    x = 34
+    
+    while false:
+      y = 999
+      break
+      
+    while true:
+      if x == 12: break
+      y = 9999
+      
+    try:
+      z = parseInt("1233")
+    except E_Base:
+      case x
+      of 34: z = 123
+      of 13: z = 34
+      else: z = 8
+  else:
+    y = 3444
+    x = 3111
+    z = 0
+  echo x, y, z
+  
+p()
diff --git a/tests/run/tpegs.nim b/tests/run/tpegs.nim
index e64cd8fef..efc6a8fa4 100644
--- a/tests/run/tpegs.nim
+++ b/tests/run/tpegs.nim
@@ -77,7 +77,7 @@ type
     of pkChar, pkGreedyRepChar: ch: char
     of pkCharChoice, pkGreedyRepSet: charChoice: ref set[char]
     of pkNonTerminal: nt: PNonTerminal
-    of pkBackRef..pkBackRefIgnoreStyle: index: range[1..MaxSubpatterns]
+    of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns]
     else: sons: seq[TNode]
   PNonTerminal* = ref TNonTerminal
   
diff --git a/todo.txt b/todo.txt
index ad0a4afa2..5b9f36dcd 100644
--- a/todo.txt
+++ b/todo.txt
@@ -2,7 +2,8 @@ version 0.9.4
 =============
 
 - make 'bind' default for templates and introduce 'mixin';
-- implement full 'not nil' checking; range[1..3] needs the same mechanism
+- test 'not nil' checking more
+- prove field accesses; prove array accesses
 - special rule for ``[]=``
 - ``=`` should be overloadable; requires specialization for ``=``; general
   lift mechanism in the compiler is already implemented for 'fields'
diff --git a/tools/niminst/debcreation.nim b/tools/niminst/debcreation.nim
index 1e08e5653..982bfaf3d 100644
--- a/tools/niminst/debcreation.nim
+++ b/tools/niminst/debcreation.nim
@@ -227,9 +227,9 @@ when isMainModule:
   
   #echo(createRules())
 
-  prepDeb("nimrod", "0.8.14", "Dominik Picheta", "morfeusz8@gmail.com", 
+  prepDeb("nimrod", "0.9.2", "Dominik Picheta", "morfeusz8@gmail.com", 
     "The Nimrod compiler", "Compiler for the Nimrod programming language",
-    @[("bin/nimrod", "gpl2"), ("lib/*", "lgpl")], 
+    @[("bin/nimrod", "MIT"), ("lib/*", "MIT")], 
     @["bin/nimrod"], @["config/*"], @["doc/*"], @["lib/*"],
     "gcc (>= 4:4.3.2)", "gcc (>= 4:4.3.2)")
 
diff --git a/web/index.txt b/web/index.txt
index 260d303c8..e504b65c4 100644
--- a/web/index.txt
+++ b/web/index.txt
@@ -89,7 +89,7 @@ Nimrod plays nice with others
 * **The Nimrod Compiler can also generate C++ or Objective C for easier
   interfacing.**
 * There are lots of bindings: for example, bindings to GTK2, the Windows API, 
-  the POSIX API, OpenGL, SDL, Cario, Python, Lua, TCL, X11, libzip, PCRE, 
+  the POSIX API, OpenGL, SDL, Cairo, Python, Lua, TCL, X11, libzip, PCRE, 
   libcurl, mySQL and SQLite are included in the standard distribution.
 * A C to Nimrod conversion utility: New bindings to C libraries are easily 
   generated by ``c2nim``.
diff --git a/web/news.txt b/web/news.txt
index d844b5012..98d3298b9 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -36,7 +36,9 @@ Language Additions
 
 - Arrays can now be declared with a single integer literal ``N`` instead of a
   range; the range is then ``0..N-1``.
-- macros.dumptree and macros.dumplisp have been made immediate, dumptree_imm and dumplisp_imm are now deprecated.
+- ``macros.dumpTree`` and ``macros.dumpLisp`` have been made ``immediate``,
+  ``dumpTreeImm`` and ``dumpLispImm`` are now deprecated.
+- Added ``requiresInit`` pragma to enforce explicit initialization.
 
 
 2013-05-20 New website design!
diff --git a/web/nimrod.ini b/web/nimrod.ini
index 36252deb6..d9c6cb786 100644
--- a/web/nimrod.ini
+++ b/web/nimrod.ini
@@ -60,7 +60,9 @@ srcdoc2: "pure/collections/intsets;pure/collections/queues;pure/encodings"
 srcdoc2: "pure/events;pure/collections/sequtils;pure/irc;pure/cookies"
 srcdoc2: "pure/ftpclient;pure/memfiles;pure/subexes;pure/collections/critbits"
 srcdoc2: "pure/asyncio;pure/actors;core/locks;pure/oids;pure/endians;pure/uri"
-srcdoc2: "pure/nimprof;pure/unittest"
+srcdoc2: "pure/nimprof;pure/unittest;packages/docutils/highlite"
+srcdoc2: "packages/docutils/rst;packages/docutils/rstast"
+srcdoc2: "packages/docutils/rstgen"
 
 webdoc: "wrappers/libcurl;pure/md5;wrappers/mysql;wrappers/iup"
 webdoc: "wrappers/sqlite3;wrappers/postgres;wrappers/tinyc"