diff options
author | Araq <rumpf_a@web.de> | 2012-11-04 18:09:15 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2012-11-04 18:09:15 +0100 |
commit | 6dd2c2d7670b11aa2155f41e1309dad011456140 (patch) | |
tree | 341a07cc2b200cac0e241a84634485c0354ae6a4 | |
parent | 9fea5b8f69758e9cb1cd2043d55fae66f3987df7 (diff) | |
download | Nim-6dd2c2d7670b11aa2155f41e1309dad011456140.tar.gz |
exception tracking should work
-rwxr-xr-x | compiler/docgen.nim | 18 | ||||
-rw-r--r-- | compiler/sempass2.nim | 57 | ||||
-rwxr-xr-x | compiler/semthreads.nim | 3 | ||||
-rw-r--r-- | tests/reject/teffects1.nim | 20 | ||||
-rw-r--r-- | tests/reject/teffects2.nim | 20 | ||||
-rwxr-xr-x | tests/run/tmultim4.nim | 4 | ||||
-rwxr-xr-x | web/index.txt | 1 |
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 |