summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2012-11-04 18:09:15 +0100
committerAraq <rumpf_a@web.de>2012-11-04 18:09:15 +0100
commit6dd2c2d7670b11aa2155f41e1309dad011456140 (patch)
tree341a07cc2b200cac0e241a84634485c0354ae6a4
parent9fea5b8f69758e9cb1cd2043d55fae66f3987df7 (diff)
downloadNim-6dd2c2d7670b11aa2155f41e1309dad011456140.tar.gz
exception tracking should work
-rwxr-xr-xcompiler/docgen.nim18
-rw-r--r--compiler/sempass2.nim57
-rwxr-xr-xcompiler/semthreads.nim3
-rw-r--r--tests/reject/teffects1.nim20
-rw-r--r--tests/reject/teffects2.nim20
-rwxr-xr-xtests/run/tmultim4.nim4
-rwxr-xr-xweb/index.txt1
7 files changed, 105 insertions, 18 deletions
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 0fc5e03cf..8bbc53b74 100755
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -14,7 +14,7 @@
 import 
   ast, strutils, strtabs, options, msgs, os, ropes, idents, 
   wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite, 
-  importer
+  importer, sempass2
 
 type
   TSections = array[TSymKind, PRope]
@@ -245,12 +245,20 @@ proc traceDeps(d: PDoc, n: PNode) =
 proc generateDoc*(d: PDoc, n: PNode) = 
   case n.kind
   of nkCommentStmt: app(d.modDesc, genComment(d, n))
-  of nkProcDef: genItem(d, n, n.sons[namePos], skProc)
-  of nkMethodDef: genItem(d, n, n.sons[namePos], skMethod)
-  of nkIteratorDef: genItem(d, n, n.sons[namePos], skIterator)
+  of nkProcDef: 
+    when useEffectSystem: documentRaises(n)
+    genItem(d, n, n.sons[namePos], skProc)
+  of nkMethodDef:
+    when useEffectSystem: documentRaises(n)
+    genItem(d, n, n.sons[namePos], skMethod)
+  of nkIteratorDef: 
+    when useEffectSystem: documentRaises(n)
+    genItem(d, n, n.sons[namePos], skIterator)
   of nkMacroDef: genItem(d, n, n.sons[namePos], skMacro)
   of nkTemplateDef: genItem(d, n, n.sons[namePos], skTemplate)
-  of nkConverterDef: genItem(d, n, n.sons[namePos], skConverter)
+  of nkConverterDef:
+    when useEffectSystem: documentRaises(n)
+    genItem(d, n, n.sons[namePos], skConverter)
   of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
     for i in countup(0, sonsLen(n) - 1):
       if n.sons[i].kind != nkCommentStmt: 
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index 4199aa5f7..1811beb2d 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -9,7 +9,7 @@
 
 import
   intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, 
-  wordrecg
+  wordrecg, strutils
 
 # Second semantic checking pass over the AST. Necessary because the old
 # way had some inherent problems. Performs:
@@ -158,7 +158,7 @@ proc trackPragmaStmt(tracked: PEffects, n: PNode) =
       # list the computed effects up to here:
       listEffects(tracked)
 
-proc raisesSpec(n: PNode): PNode =
+proc raisesSpec*(n: PNode): PNode =
   for i in countup(0, sonsLen(n) - 1):
     var it = n.sons[i]
     if it.kind == nkExprColonExpr and whichPragma(it) == wRaises:
@@ -168,26 +168,62 @@ proc raisesSpec(n: PNode): PNode =
         result.add(it.sons[1])
       return
 
+proc documentRaises*(n: PNode) =
+  if n.sons[namePos].kind != nkSym: return
+
+  var x = n.sons[pragmasPos]
+  let spec = raisesSpec(x)
+  if isNil(spec):
+    let s = n.sons[namePos].sym
+    
+    let actual = s.typ.n.sons[0]
+    if actual.len != effectListLen: return
+    let real = actual.sons[exceptionEffects]
+    
+    # warning: hack ahead: 
+    var effects = newNodeI(nkBracket, n.info, real.len)
+    for i in 0 .. <real.len:
+      var t = typeToString(real[i].typ)
+      if t.startsWith("ref "): t = substr(t, 4)
+      effects.sons[i] = newIdentNode(getIdent(t), n.info)
+
+    var pair = newNode(nkExprColonExpr, n.info, @[
+      newIdentNode(getIdent"raises", n.info), effects])
+    
+    if x.kind == nkEmpty:
+      x = newNodeI(nkPragma, n.info)
+      n.sons[pragmasPos] = x
+    x.add(pair)
+
 proc createRaise(n: PNode): PNode =
   result = newNodeIT(nkType, n.info, sysTypeFromName"E_Base")
 
 proc track(tracked: PEffects, n: PNode) =
   case n.kind
-  of nkRaiseStmt: throws(tracked, n.sons[0])
+  of nkRaiseStmt: 
+    n.sons[0].info = n.info
+    throws(tracked, n.sons[0])
   of nkCallKinds:
     # p's effects are ours too:
-    let op = n.sons[0].typ
+    let a = n.sons[0]
+    let op = a.typ
     if op != nil and op.kind == tyProc:
       InternalAssert op.n.sons[0].kind == nkEffectList
       var effectList = op.n.sons[0]
-      if effectList.len == 0:
-        if isForwardedProc(n.sons[0]):
-          let spec = raisesSpec(n.sons[0].sym.ast.sons[pragmasPos])
+      if a.kind == nkSym and a.sym.kind == skMethod:
+        let spec = raisesSpec(a.sym.ast.sons[pragmasPos])
+        if not isNil(spec):
+          mergeEffects(tracked, spec, useLineInfo=false)
+        else:
+          addEffect(tracked, createRaise(n))
+      elif effectList.len == 0:
+        if isForwardedProc(a):
+          let spec = raisesSpec(a.sym.ast.sons[pragmasPos])
           if not isNil(spec):
             mergeEffects(tracked, spec, useLineInfo=false)
           else:
             addEffect(tracked, createRaise(n))
-        elif isIndirectCall(n.sons[0]):
+        elif isIndirectCall(a):
           addEffect(tracked, createRaise(n))
       else:
         effectList = effectList.sons[exceptionEffects]
@@ -204,8 +240,7 @@ proc track(tracked: PEffects, n: PNode) =
     track(tracked, n.sons[i])
 
 # XXX
-# - doc2 should report effects
-# - check for 'raises' consistency for multi-methods
+# - more tests
 
 proc checkRaisesSpec(spec, real: PNode) =
   # check that any real exception is listed in 'spec'; mark those as used;
@@ -218,6 +253,7 @@ proc checkRaisesSpec(spec, real: PNode) =
           used.incl(s)
           break search
       # XXX call graph analysis would be nice here!
+      localError(spec.info, errInstantiationFrom)
       localError(r.info, errGenerated, "can raise an unlisted exception: " &
         typeToString(r.typ))
   # hint about unnecessarily listed exception types:
@@ -238,6 +274,7 @@ proc checkMethodEffects*(disp, branch: PSym) =
         for s in 0 .. <spec.len:
           if inheritanceDiff(r.excType, spec[s].typ) <= 0:
             break search
+        localError(branch.info, errInstantiationFrom)
         localError(r.info, errGenerated, "can raise an unlisted exception: " &
           typeToString(r.typ))
 
diff --git a/compiler/semthreads.nim b/compiler/semthreads.nim
index 09668a912..6c0259ef1 100755
--- a/compiler/semthreads.nim
+++ b/compiler/semthreads.nim
@@ -360,7 +360,8 @@ proc analyse(c: PProcCtx, n: PNode): TThreadOwner =
     if n.sons[0].kind != nkEmpty: result = analyse(c, n.sons[0])
     else: result = toVoid
   of nkAsmStmt, nkPragma, nkIteratorDef, nkProcDef, nkMethodDef,
-     nkConverterDef, nkMacroDef, nkTemplateDef, nkLambdaKinds: 
+     nkConverterDef, nkMacroDef, nkTemplateDef, nkLambdaKinds, nkClosure,
+     nkGotoState, nkState: 
       result = toVoid
   of nkExprColonExpr:
     result = analyse(c, n.sons[1])
diff --git a/tests/reject/teffects1.nim b/tests/reject/teffects1.nim
new file mode 100644
index 000000000..a6702df83
--- /dev/null
+++ b/tests/reject/teffects1.nim
@@ -0,0 +1,20 @@
+discard """
+  line: 16
+  errormsg: "instantiation from here"
+"""
+
+type
+  TObj = object {.pure, inheritable.}
+  TObjB = object of TObj
+    a, b, c: string
+  
+  EIO2 = ref object of EIO
+  
+proc forw: int {. .}
+  
+proc lier(): int {.raises: [EIO2].} =
+  writeln stdout, "arg"
+
+proc forw: int =
+  raise newException(EIO, "arg")
+
diff --git a/tests/reject/teffects2.nim b/tests/reject/teffects2.nim
new file mode 100644
index 000000000..51b583411
--- /dev/null
+++ b/tests/reject/teffects2.nim
@@ -0,0 +1,20 @@
+discard """
+  line: 13
+  errormsg: "instantiation from here"
+"""
+
+type
+  TObj = object {.pure, inheritable.}
+  TObjB = object of TObj
+    a, b, c: string
+  
+  EIO2 = ref object of EIO
+  
+proc forw: int {.raises: [].}
+
+proc lier(): int {.raises: [EIO].} =
+  writeln stdout, "arg"
+
+proc forw: int =
+  raise newException(EIO, "arg")
+
diff --git a/tests/run/tmultim4.nim b/tests/run/tmultim4.nim
index 6bb7970dd..d824086b2 100755
--- a/tests/run/tmultim4.nim
+++ b/tests/run/tmultim4.nim
@@ -5,11 +5,13 @@ discard """
 type
   Test = object of TObject
 
-method doMethod(a: ref TObject) =
+method doMethod(a: ref TObject) {.raises: [EIO].} =
   quit "override"
 
 method doMethod(a: ref Test) =
   echo "hello"
+  if a == nil:
+    raise newException(EIO, "arg")
 
 proc doProc(a: ref Test) =
   echo "hello"
diff --git a/web/index.txt b/web/index.txt
index 03f11ed49..25853867a 100755
--- a/web/index.txt
+++ b/web/index.txt
@@ -111,5 +111,4 @@ Version 0.9.x
   * message passing performance will be greatly improved
   * the syntactic distinction between statements and expressions will be
     removed
-  * exception tracking
   * the need for forward declarations may be removed