summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2013-06-13 15:19:55 +0200
committerAraq <rumpf_a@web.de>2013-06-13 15:19:55 +0200
commitff1d68c50b5df56645eb09a523c08726772bec4d (patch)
treee6a3a39f95c381abfe50499902afa7e57dc83204
parent2464da5b261937f70400c1ca2b3ef9786743cef0 (diff)
downloadNim-ff1d68c50b5df56645eb09a523c08726772bec4d.tar.gz
fixes #481
-rw-r--r--compiler/guards.nim19
-rw-r--r--compiler/sempass2.nim9
-rw-r--r--tests/reject/tnotnil1.nim15
3 files changed, 41 insertions, 2 deletions
diff --git a/compiler/guards.nim b/compiler/guards.nim
index aece63b19..f02a53684 100644
--- a/compiler/guards.nim
+++ b/compiler/guards.nim
@@ -345,12 +345,22 @@ proc impliesIn(fact, loc, aSet: PNode): TImplication =
       result = geImpliesIn(fact.sons[2], fact.sons[1].pred, aSet)
   of mNot, mOr, mAnd: internalError(loc.info, "impliesIn")
   else: discard
-  
+
+proc valueIsNil(n: PNode): TImplication =
+  if n.kind == nkNilLit: impYes
+  elif n.kind in {nkStrLit..nkTripleStrLit, nkBracket, nkObjConstr}: impNo
+  else: impUnknown
+
 proc impliesIsNil(fact, eq: PNode): TImplication =
   case fact.sons[0].sym.magic
   of mIsNil:
     if sameTree(fact.sons[1], eq.sons[1]):
       result = impYes
+  of someEq:
+    if sameTree(fact.sons[1], eq.sons[1]):
+      result = valueIsNil(fact.sons[2].skipConv)
+    elif sameTree(fact.sons[2], eq.sons[1]):
+      result = valueIsNil(fact.sons[1].skipConv)
   of mNot, mOr, mAnd: internalError(eq.info, "impliesIsNil")
   else: discard
 
@@ -539,6 +549,13 @@ proc addDiscriminantFact*(m: var TModel, n: PNode) =
   fact.sons[2] = n.sons[1]
   m.add fact
 
+proc addAsgnFact*(m: var TModel, key, value: PNode) =
+  var fact = newNodeI(nkCall, key.info, 3)
+  fact.sons[0] = newSymNode(getSysMagic("==", mEqI))
+  fact.sons[1] = key
+  fact.sons[2] = value
+  m.add fact
+
 proc addCaseBranchFacts*(m: var TModel, n: PNode, i: int) =
   let branch = n.sons[i]
   if branch.kind == nkOfBranch:
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index 2c87c3b2c..1fc74d31c 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -309,6 +309,12 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
   let n = n.skipConv
   if paramType != nil and tfNotNil in paramType.flags and 
       n.typ != nil and tfNotNil notin n.typ.flags:
+    if n.kind == nkAddr:
+      # addr(x[]) can't be proven, but addr(x) can:
+      if not containsNode(n, {nkDerefExpr, nkHiddenDeref}): return
+    elif n.kind == nkSym and n.sym.kind in RoutineKinds:
+      # 'p' is not nil obviously:
+      return
     case impliesNotNil(tracked.guards, n)
     of impUnknown:
       Message(n.info, errGenerated, 
@@ -481,6 +487,7 @@ proc track(tracked: PEffects, n: PNode) =
     initVar(tracked, n.sons[0])
     invalidateFacts(tracked.guards, n.sons[0])
     track(tracked, n.sons[0])
+    addAsgnFact(tracked.guards, n.sons[0], n.sons[1])
     notNilCheck(tracked, n.sons[1], n.sons[0].typ)
   of nkVarSection:
     for child in n:
@@ -489,6 +496,7 @@ proc track(tracked: PEffects, n: PNode) =
         track(tracked, last)
         for i in 0 .. child.len-3:
           initVar(tracked, child.sons[i])
+          addAsgnFact(tracked.guards, child.sons[i], last)
           notNilCheck(tracked, last, child.sons[i].typ)
       # since 'var (a, b): T = ()' is not even allowed, there is always type
       # inference for (a, b) and thus no nil checking is necessary.
@@ -523,6 +531,7 @@ proc track(tracked: PEffects, n: PNode) =
       if sfDiscriminant in x.sons[0].sym.flags:
         addDiscriminantFact(tracked.guards, x)
     setLen(tracked.guards, oldFacts)
+  of nkTypeSection: discard
   else:
     for i in 0 .. <safeLen(n): track(tracked, n.sons[i])
 
diff --git a/tests/reject/tnotnil1.nim b/tests/reject/tnotnil1.nim
index 222c77376..863fe45f8 100644
--- a/tests/reject/tnotnil1.nim
+++ b/tests/reject/tnotnil1.nim
@@ -1,6 +1,6 @@
 discard """
   errormsg: "'y' is provably nil"
-  line:25
+  line:38
 """
 
 import strutils
@@ -10,6 +10,19 @@ type
   TObj = object
     x, y: int
 
+type
+  superstring = string not nil
+
+
+proc q(s: superstring) =
+  echo s
+
+proc p2() =
+  var  a: string = "I am not nil" 
+  q(a) # but this should and does not
+
+p2()
+
 proc q(x: pointer not nil) =
   nil