exception tracking should work
This commit is contained in:
parent
9fea5b8f69
commit
6dd2c2d767
7 changed files with 105 additions and 18 deletions
|
|
@ -14,7 +14,7 @@
|
||||||
import
|
import
|
||||||
ast, strutils, strtabs, options, msgs, os, ropes, idents,
|
ast, strutils, strtabs, options, msgs, os, ropes, idents,
|
||||||
wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite,
|
wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite,
|
||||||
importer
|
importer, sempass2
|
||||||
|
|
||||||
type
|
type
|
||||||
TSections = array[TSymKind, PRope]
|
TSections = array[TSymKind, PRope]
|
||||||
|
|
@ -245,12 +245,20 @@ proc traceDeps(d: PDoc, n: PNode) =
|
||||||
proc generateDoc*(d: PDoc, n: PNode) =
|
proc generateDoc*(d: PDoc, n: PNode) =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkCommentStmt: app(d.modDesc, genComment(d, n))
|
of nkCommentStmt: app(d.modDesc, genComment(d, n))
|
||||||
of nkProcDef: genItem(d, n, n.sons[namePos], skProc)
|
of nkProcDef:
|
||||||
of nkMethodDef: genItem(d, n, n.sons[namePos], skMethod)
|
when useEffectSystem: documentRaises(n)
|
||||||
of nkIteratorDef: genItem(d, n, n.sons[namePos], skIterator)
|
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 nkMacroDef: genItem(d, n, n.sons[namePos], skMacro)
|
||||||
of nkTemplateDef: genItem(d, n, n.sons[namePos], skTemplate)
|
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:
|
of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
if n.sons[i].kind != nkCommentStmt:
|
if n.sons[i].kind != nkCommentStmt:
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
|
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
|
||||||
wordrecg
|
wordrecg, strutils
|
||||||
|
|
||||||
# Second semantic checking pass over the AST. Necessary because the old
|
# Second semantic checking pass over the AST. Necessary because the old
|
||||||
# way had some inherent problems. Performs:
|
# way had some inherent problems. Performs:
|
||||||
|
|
@ -158,7 +158,7 @@ proc trackPragmaStmt(tracked: PEffects, n: PNode) =
|
||||||
# list the computed effects up to here:
|
# list the computed effects up to here:
|
||||||
listEffects(tracked)
|
listEffects(tracked)
|
||||||
|
|
||||||
proc raisesSpec(n: PNode): PNode =
|
proc raisesSpec*(n: PNode): PNode =
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
if it.kind == nkExprColonExpr and whichPragma(it) == wRaises:
|
if it.kind == nkExprColonExpr and whichPragma(it) == wRaises:
|
||||||
|
|
@ -168,26 +168,62 @@ proc raisesSpec(n: PNode): PNode =
|
||||||
result.add(it.sons[1])
|
result.add(it.sons[1])
|
||||||
return
|
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 =
|
proc createRaise(n: PNode): PNode =
|
||||||
result = newNodeIT(nkType, n.info, sysTypeFromName"E_Base")
|
result = newNodeIT(nkType, n.info, sysTypeFromName"E_Base")
|
||||||
|
|
||||||
proc track(tracked: PEffects, n: PNode) =
|
proc track(tracked: PEffects, n: PNode) =
|
||||||
case n.kind
|
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:
|
of nkCallKinds:
|
||||||
# p's effects are ours too:
|
# 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:
|
if op != nil and op.kind == tyProc:
|
||||||
InternalAssert op.n.sons[0].kind == nkEffectList
|
InternalAssert op.n.sons[0].kind == nkEffectList
|
||||||
var effectList = op.n.sons[0]
|
var effectList = op.n.sons[0]
|
||||||
if effectList.len == 0:
|
if a.kind == nkSym and a.sym.kind == skMethod:
|
||||||
if isForwardedProc(n.sons[0]):
|
let spec = raisesSpec(a.sym.ast.sons[pragmasPos])
|
||||||
let spec = raisesSpec(n.sons[0].sym.ast.sons[pragmasPos])
|
|
||||||
if not isNil(spec):
|
if not isNil(spec):
|
||||||
mergeEffects(tracked, spec, useLineInfo=false)
|
mergeEffects(tracked, spec, useLineInfo=false)
|
||||||
else:
|
else:
|
||||||
addEffect(tracked, createRaise(n))
|
addEffect(tracked, createRaise(n))
|
||||||
elif isIndirectCall(n.sons[0]):
|
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(a):
|
||||||
addEffect(tracked, createRaise(n))
|
addEffect(tracked, createRaise(n))
|
||||||
else:
|
else:
|
||||||
effectList = effectList.sons[exceptionEffects]
|
effectList = effectList.sons[exceptionEffects]
|
||||||
|
|
@ -204,8 +240,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||||
track(tracked, n.sons[i])
|
track(tracked, n.sons[i])
|
||||||
|
|
||||||
# XXX
|
# XXX
|
||||||
# - doc2 should report effects
|
# - more tests
|
||||||
# - check for 'raises' consistency for multi-methods
|
|
||||||
|
|
||||||
proc checkRaisesSpec(spec, real: PNode) =
|
proc checkRaisesSpec(spec, real: PNode) =
|
||||||
# check that any real exception is listed in 'spec'; mark those as used;
|
# 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)
|
used.incl(s)
|
||||||
break search
|
break search
|
||||||
# XXX call graph analysis would be nice here!
|
# XXX call graph analysis would be nice here!
|
||||||
|
localError(spec.info, errInstantiationFrom)
|
||||||
localError(r.info, errGenerated, "can raise an unlisted exception: " &
|
localError(r.info, errGenerated, "can raise an unlisted exception: " &
|
||||||
typeToString(r.typ))
|
typeToString(r.typ))
|
||||||
# hint about unnecessarily listed exception types:
|
# hint about unnecessarily listed exception types:
|
||||||
|
|
@ -238,6 +274,7 @@ proc checkMethodEffects*(disp, branch: PSym) =
|
||||||
for s in 0 .. <spec.len:
|
for s in 0 .. <spec.len:
|
||||||
if inheritanceDiff(r.excType, spec[s].typ) <= 0:
|
if inheritanceDiff(r.excType, spec[s].typ) <= 0:
|
||||||
break search
|
break search
|
||||||
|
localError(branch.info, errInstantiationFrom)
|
||||||
localError(r.info, errGenerated, "can raise an unlisted exception: " &
|
localError(r.info, errGenerated, "can raise an unlisted exception: " &
|
||||||
typeToString(r.typ))
|
typeToString(r.typ))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -360,7 +360,8 @@ proc analyse(c: PProcCtx, n: PNode): TThreadOwner =
|
||||||
if n.sons[0].kind != nkEmpty: result = analyse(c, n.sons[0])
|
if n.sons[0].kind != nkEmpty: result = analyse(c, n.sons[0])
|
||||||
else: result = toVoid
|
else: result = toVoid
|
||||||
of nkAsmStmt, nkPragma, nkIteratorDef, nkProcDef, nkMethodDef,
|
of nkAsmStmt, nkPragma, nkIteratorDef, nkProcDef, nkMethodDef,
|
||||||
nkConverterDef, nkMacroDef, nkTemplateDef, nkLambdaKinds:
|
nkConverterDef, nkMacroDef, nkTemplateDef, nkLambdaKinds, nkClosure,
|
||||||
|
nkGotoState, nkState:
|
||||||
result = toVoid
|
result = toVoid
|
||||||
of nkExprColonExpr:
|
of nkExprColonExpr:
|
||||||
result = analyse(c, n.sons[1])
|
result = analyse(c, n.sons[1])
|
||||||
|
|
|
||||||
20
tests/reject/teffects1.nim
Normal file
20
tests/reject/teffects1.nim
Normal file
|
|
@ -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")
|
||||||
|
|
||||||
20
tests/reject/teffects2.nim
Normal file
20
tests/reject/teffects2.nim
Normal file
|
|
@ -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")
|
||||||
|
|
||||||
|
|
@ -5,11 +5,13 @@ discard """
|
||||||
type
|
type
|
||||||
Test = object of TObject
|
Test = object of TObject
|
||||||
|
|
||||||
method doMethod(a: ref TObject) =
|
method doMethod(a: ref TObject) {.raises: [EIO].} =
|
||||||
quit "override"
|
quit "override"
|
||||||
|
|
||||||
method doMethod(a: ref Test) =
|
method doMethod(a: ref Test) =
|
||||||
echo "hello"
|
echo "hello"
|
||||||
|
if a == nil:
|
||||||
|
raise newException(EIO, "arg")
|
||||||
|
|
||||||
proc doProc(a: ref Test) =
|
proc doProc(a: ref Test) =
|
||||||
echo "hello"
|
echo "hello"
|
||||||
|
|
|
||||||
|
|
@ -111,5 +111,4 @@ Version 0.9.x
|
||||||
* message passing performance will be greatly improved
|
* message passing performance will be greatly improved
|
||||||
* the syntactic distinction between statements and expressions will be
|
* the syntactic distinction between statements and expressions will be
|
||||||
removed
|
removed
|
||||||
* exception tracking
|
|
||||||
* the need for forward declarations may be removed
|
* the need for forward declarations may be removed
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue