diff options
author | Araq <rumpf_a@web.de> | 2012-11-03 15:57:12 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2012-11-03 15:57:12 +0100 |
commit | 9f38ff0c6578a7030b85acf66363d8f4e51dbe33 (patch) | |
tree | b2e353df34715c8eae026341c8ea0368db4cebbd | |
parent | 224f42bbd70c9c39e6c93bc7c0cf9568e79e115b (diff) | |
download | Nim-9f38ff0c6578a7030b85acf66363d8f4e51dbe33.tar.gz |
next steps for exception tracking
-rwxr-xr-x | compiler/cgmeth.nim | 11 | ||||
-rwxr-xr-x | compiler/options.nim | 2 | ||||
-rwxr-xr-x | compiler/sem.nim | 2 | ||||
-rw-r--r-- | compiler/sempass2.nim | 64 | ||||
-rwxr-xr-x | compiler/semtypes.nim | 3 | ||||
-rwxr-xr-x | compiler/sigmatch.nim | 2 | ||||
-rwxr-xr-x | compiler/types.nim | 23 |
7 files changed, 73 insertions, 34 deletions
diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 76f5414ec..687653aaf 100755 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -10,7 +10,8 @@ ## This module implements code generation for multi methods. import - intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys + intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys, + sempass2 proc genConv(n: PNode, d: PType, downcast: bool): PNode = var dest = skipTypes(d, abstractPtrs) @@ -81,10 +82,12 @@ proc attachDispatcher(s: PSym, dispatcher: PNode) = proc methodDef*(s: PSym, fromCache: bool) = var L = len(gMethods) - for i in countup(0, L - 1): - if sameMethodBucket(gMethods[i][0], s): + for i in countup(0, L - 1): + let disp = gMethods[i][0] + if sameMethodBucket(disp, s): add(gMethods[i], s) - attachDispatcher(s, lastSon(gMethods[i][0].ast)) + attachDispatcher(s, lastSon(disp.ast)) + when useEffectSystem: checkMethodEffects(disp, s) return add(gMethods, @[s]) # create a new dispatcher: diff --git a/compiler/options.nim b/compiler/options.nim index f5e54a613..2051953ce 100755 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -12,7 +12,7 @@ import const hasTinyCBackend* = defined(tinyc) - useEffectSystem* = false + useEffectSystem* = true type # please make sure we have under 32 options # (improves code efficiency a lot!) diff --git a/compiler/sem.nim b/compiler/sem.nim index 93d023806..bd1ad1468 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -15,7 +15,7 @@ import magicsys, parser, nversion, nimsets, semfold, importer, procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch, semthreads, intsets, transf, evals, idgen, aliases, cgmeth, lambdalifting, - evaltempl, patterns, parampatterns + evaltempl, patterns, parampatterns, sempass2 proc semPass*(): TPass # implementation diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 936fe1822..4199aa5f7 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -25,7 +25,7 @@ import # io, time (time dependent), gc (performs GC'ed allocation), exceptions, # side effect (accesses global), store (stores into *type*), # store_unkown (performs some store) --> store(any)|store(x) -# load (loads from *type*), recursive (recursive call), +# load (loads from *type*), recursive (recursive call), unsafe, # endless (has endless loops), --> user effects are defined over *patterns* # --> a TR macro can annotate the proc with user defined annotations # --> the effect system can access these @@ -84,20 +84,16 @@ type PEffects = var TEffects proc throws(tracked: PEffects, n: PNode) = - # since a 'raise' statement occurs rarely and we need distinct reasons; - # we simply do not merge anything here, this would be problematic for the - # stack of exceptions anyway: tracked.exc.add n proc excType(n: PNode): PType = - assert n.kind == nkRaiseStmt + assert n.kind != nkRaiseStmt # reraise is like raising E_Base: - let t = if n.sons[0].kind == nkEmpty: sysTypeFromName"E_Base" - else: n.sons[0].typ + let t = if n.kind == nkEmpty: sysTypeFromName"E_Base" else: n.typ result = skipTypes(t, skipPtrs) proc addEffect(a: PEffects, e: PNode, useLineInfo=true) = - assert e.kind == nkRaiseStmt + assert e.kind != nkRaiseStmt var aa = a.exc for i in a.bottom .. <aa.len: if sameType(aa[i].excType, e.excType): @@ -111,7 +107,7 @@ proc mergeEffects(a: PEffects, b: PNode, useLineInfo) = proc listEffects(a: PEffects) = var aa = a.exc for e in items(aa): - Message(e.info, hintUser, renderTree(e)) + Message(e.info, hintUser, typeToString(e.typ)) proc catches(tracked: PEffects, e: PType) = let e = skipTypes(e, skipPtrs) @@ -172,13 +168,12 @@ proc raisesSpec(n: PNode): PNode = result.add(it.sons[1]) return -proc createRaise(n: PNode, t: PType): PNode = - result = newNodeI(nkRaiseStmt, n.info) - result.add(newNodeIT(nkType, n.info, t)) +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) + of nkRaiseStmt: throws(tracked, n.sons[0]) of nkCallKinds: # p's effects are ours too: let op = n.sons[0].typ @@ -191,9 +186,9 @@ proc track(tracked: PEffects, n: PNode) = if not isNil(spec): mergeEffects(tracked, spec, useLineInfo=false) else: - addEffect(tracked, createRaise(n, sysTypeFromName"E_Base")) + addEffect(tracked, createRaise(n)) elif isIndirectCall(n.sons[0]): - addEffect(tracked, createRaise(n, sysTypeFromName"E_Base")) + addEffect(tracked, createRaise(n)) else: effectList = effectList.sons[exceptionEffects] mergeEffects(tracked, effectList, useLineInfo=true) @@ -209,7 +204,7 @@ proc track(tracked: PEffects, n: PNode) = track(tracked, n.sons[i]) # XXX -# - make use of 'raises' in proc types compatibility +# - doc2 should report effects # - check for 'raises' consistency for multi-methods proc checkRaisesSpec(spec, real: PNode) = @@ -224,22 +219,37 @@ proc checkRaisesSpec(spec, real: PNode) = break search # XXX call graph analysis would be nice here! localError(r.info, errGenerated, "can raise an unlisted exception: " & - typeToString(r.sons[0].typ)) + typeToString(r.typ)) # hint about unnecessarily listed exception types: for s in 0 .. <spec.len: if not used.contains(s): Message(spec[s].info, hintXDeclaredButNotUsed, renderTree(spec[s])) -proc compatibleEffects*(formal, actual: PType): bool = - # for proc type compatibility checking: - assert formal.kind == tyProc and actual.kind == tyProc - InternalAssert formal.n.sons[0].kind == nkEffectList - InternalAssert actual.n.sons[0].kind == nkEffectList - - var effectList = formal.n.sons[0] - if effectList.len == 0: - # 'formal' has no restrictions :-) - result = true +proc checkMethodEffects*(disp, branch: PSym) = + ## checks for consistent effects for multi methods. + let spec = raisesSpec(disp.ast.sons[pragmasPos]) + if not isNil(spec): + let actual = branch.typ.n.sons[0] + if actual.len != effectListLen: return + let real = actual.sons[exceptionEffects] + + for r in items(real): + block search: + for s in 0 .. <spec.len: + if inheritanceDiff(r.excType, spec[s].typ) <= 0: + break search + localError(r.info, errGenerated, "can raise an unlisted exception: " & + typeToString(r.typ)) + +proc setEffectsForProcType*(t: PType, n: PNode) = + var effects = t.n.sons[0] + InternalAssert t.kind == tyProc and effects.kind == nkEffectList + + let spec = raisesSpec(n) + if not isNil(spec): + InternalAssert effects.len == 0 + newSeq(effects.sons, effectListLen) + effects.sons[exceptionEffects] = spec proc trackProc*(s: PSym, body: PNode) = var effects = s.typ.n.sons[0] diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 00be65203..6716693ca 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -893,9 +893,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = if n.sons[1].kind == nkEmpty or n.sons[1].len == 0: if result.callConv == ccDefault: result.callConv = ccClosure - Message(n.info, warnImplicitClosure, renderTree(n)) + #Message(n.info, warnImplicitClosure, renderTree(n)) else: pragma(c, s, n.sons[1], procTypePragmas) + when useEffectSystem: SetEffectsForProcType(result, n.sons[1]) closeScope(c.tab) of nkEnumTy: result = semEnum(c, n, prev) of nkType: result = n.typ diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 3205866d1..0b9244c2a 100755 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -297,6 +297,8 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = result = isConvertible else: return isNone + when useEffectSystem: + if not compatibleEffects(f, a): return isNone else: nil proc matchTypeClass(c: var TCandidate, f, a: PType): TTypeRelation = diff --git a/compiler/types.nim b/compiler/types.nim index 7b7078e20..7ee69a59a 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1189,3 +1189,26 @@ proc baseOfDistinct*(t: PType): PType = if it.kind == tyDistinct: internalAssert parent != nil parent.sons[0] = it.sons[0] + +proc compatibleEffects*(formal, actual: PType): bool = + # for proc type compatibility checking: + assert formal.kind == tyProc and actual.kind == tyProc + InternalAssert formal.n.sons[0].kind == nkEffectList + InternalAssert actual.n.sons[0].kind == nkEffectList + + var spec = formal.n.sons[0] + # if 'spec.sons[0].kind == nkArgList' it is no formal type really, but a + # computed effect and as such no spec: + # 'r.msgHandler = if isNil(msgHandler): defaultMsgHandler else: msgHandler' + if spec.len != 0 and spec.sons[0].kind != nkArgList: + var real = actual.n.sons[0] + if real.len == 0: + # we don't know anything about 'real' ... + return false + for r in items(real): + block search: + for s in items(spec): + if inheritanceDiff(r.typ, s.typ) <= 0: + break search + return false + result = true |