implemented 'tags' pragma

This commit is contained in:
Araq 2012-11-11 22:03:41 +01:00
commit 48a62af3b1
9 changed files with 193 additions and 88 deletions

View file

@ -24,7 +24,7 @@ const
wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge, wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC, wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
wNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wHoist, wNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wHoist,
wGenSym, wInject, wRaises} wGenSym, wInject, wRaises, wTags}
converterPragmas* = procPragmas converterPragmas* = procPragmas
methodPragmas* = procPragmas methodPragmas* = procPragmas
templatePragmas* = {wImmediate, wDeprecated, wError, wGenSym, wInject, wDirty} templatePragmas* = {wImmediate, wDeprecated, wError, wGenSym, wInject, wDirty}
@ -33,7 +33,8 @@ const
wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject} wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject}
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect, iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect,
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern, wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject, wRaises} wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject, wRaises,
wTags}
exprPragmas* = {wLine} exprPragmas* = {wLine}
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks, stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
@ -45,7 +46,7 @@ const
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader,
wDeprecated, wExtern, wThread, wImportcpp, wImportobjc, wNoStackFrame, wDeprecated, wExtern, wThread, wImportcpp, wImportobjc, wNoStackFrame,
wRaises} wRaises, wTags}
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl, typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern, wShallow, wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern, wShallow,
wImportcpp, wImportobjc, wError, wIncompleteStruct, wByCopy, wByRef, wImportcpp, wImportobjc, wError, wIncompleteStruct, wByCopy, wByRef,
@ -60,7 +61,7 @@ const
wExtern, wImportcpp, wImportobjc, wError, wGenSym, wInject} wExtern, wImportcpp, wImportobjc, wError, wGenSym, wInject}
letPragmas* = varPragmas letPragmas* = varPragmas
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideEffect, procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideEffect,
wThread, wRaises} wThread, wRaises, wTags}
allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
@ -464,11 +465,11 @@ proc processPragma(c: PContext, n: PNode, i: int) =
userPragma.ast = body userPragma.ast = body
StrTableAdd(c.userPragmas, userPragma) StrTableAdd(c.userPragmas, userPragma)
proc pragmaRaises(c: PContext, n: PNode) = proc pragmaRaisesOrTags(c: PContext, n: PNode) =
proc processExc(c: PContext, x: PNode) = proc processExc(c: PContext, x: PNode) =
var t = skipTypes(c.semTypeNode(c, x, nil), skipPtrs) var t = skipTypes(c.semTypeNode(c, x, nil), skipPtrs)
if t.kind != tyObject: if t.kind != tyObject:
localError(x.info, errGenerated, "invalid exception type") localError(x.info, errGenerated, "invalid type for raises/tags list")
x.typ = t x.typ = t
if n.kind == nkExprColonExpr: if n.kind == nkExprColonExpr:
@ -696,7 +697,7 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
noVal(it) noVal(it)
if sym == nil: invalidPragma(it) if sym == nil: invalidPragma(it)
of wLine: PragmaLine(c, it) of wLine: PragmaLine(c, it)
of wRaises: pragmaRaises(c, it) of wRaises, wTags: pragmaRaisesOrTags(c, it)
else: invalidPragma(it) else: invalidPragma(it)
else: invalidPragma(it) else: invalidPragma(it)
else: processNote(c, it) else: processNote(c, it)

View file

@ -53,7 +53,7 @@ when false:
assert n.kind == nkSym assert n.kind == nkSym
# ------------------------ exception tracking ------------------------------- # ------------------------ exception and tag tracking -------------------------
discard """ discard """
exception tracking: exception tracking:
@ -79,15 +79,15 @@ discard """
type type
TEffects = object TEffects = object
exc: PNode # stack of exceptions exc: PNode # stack of exceptions
tags: PNode # list of tags
bottom: int bottom: int
PEffects = var TEffects PEffects = var TEffects
proc throws(tracked: PEffects, n: PNode) = proc throws(tracked, n: PNode) =
if n.typ == nil or n.typ.kind != tyError: tracked.exc.add n if n.typ == nil or n.typ.kind != tyError: tracked.add n
proc excType(n: PNode): PType = proc excType(n: PNode): PType =
assert n.kind != nkRaiseStmt
# reraise is like raising E_Base: # reraise is like raising E_Base:
let t = if n.kind == nkEmpty: sysTypeFromName"E_Base" else: n.typ let t = if n.kind == nkEmpty: sysTypeFromName"E_Base" else: n.typ
result = skipTypes(t, skipPtrs) result = skipTypes(t, skipPtrs)
@ -99,15 +99,25 @@ proc addEffect(a: PEffects, e: PNode, useLineInfo=true) =
if sameType(aa[i].excType, e.excType): if sameType(aa[i].excType, e.excType):
if not useLineInfo: return if not useLineInfo: return
elif aa[i].info == e.info: return elif aa[i].info == e.info: return
throws(a, e) throws(a.exc, e)
proc mergeEffects(a: PEffects, b: PNode, useLineInfo) = proc mergeEffects(a: PEffects, b: PNode, useLineInfo: bool) =
for effect in items(b): addEffect(a, effect, useLineInfo) for effect in items(b): addEffect(a, effect, useLineInfo)
proc addTag(a: PEffects, e: PNode, useLineInfo=true) =
var aa = a.tags
for i in 0 .. <aa.len:
if sameType(aa[i].typ.skipTypes(skipPtrs), e.typ.skipTypes(skipPtrs)):
if not useLineInfo: return
elif aa[i].info == e.info: return
throws(a.tags, e)
proc mergeTags(a: PEffects, b: PNode, useLineInfo: bool) =
for effect in items(b): addTag(a, effect, useLineInfo)
proc listEffects(a: PEffects) = proc listEffects(a: PEffects) =
var aa = a.exc for e in items(a.exc): Message(e.info, hintUser, typeToString(e.typ))
for e in items(aa): for e in items(a.tags): Message(e.info, hintUser, typeToString(e.typ))
Message(e.info, hintUser, typeToString(e.typ))
proc catches(tracked: PEffects, e: PType) = proc catches(tracked: PEffects, e: PType) =
let e = skipTypes(e, skipPtrs) let e = skipTypes(e, skipPtrs)
@ -159,27 +169,25 @@ 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 effectSpec(n: PNode, effectType = wRaises): 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) == effectType:
result = it.sons[1] result = it.sons[1]
if result.kind notin {nkCurly, nkBracket}: if result.kind notin {nkCurly, nkBracket}:
result = newNodeI(nkCurly, result.info) result = newNodeI(nkCurly, result.info)
result.add(it.sons[1]) result.add(it.sons[1])
return return
proc documentRaises*(n: PNode) = proc documentEffect(n, x: PNode, effectType: TSpecialWord, idx: int) =
if n.sons[namePos].kind != nkSym: return var x = x
let spec = effectSpec(x, effectType)
var x = n.sons[pragmasPos]
let spec = raisesSpec(x)
if isNil(spec): if isNil(spec):
let s = n.sons[namePos].sym let s = n.sons[namePos].sym
let actual = s.typ.n.sons[0] let actual = s.typ.n.sons[0]
if actual.len != effectListLen: return if actual.len != effectListLen: return
let real = actual.sons[exceptionEffects] let real = actual.sons[idx]
# warning: hack ahead: # warning: hack ahead:
var effects = newNodeI(nkBracket, n.info, real.len) var effects = newNodeI(nkBracket, n.info, real.len)
@ -189,21 +197,45 @@ proc documentRaises*(n: PNode) =
effects.sons[i] = newIdentNode(getIdent(t), n.info) effects.sons[i] = newIdentNode(getIdent(t), n.info)
var pair = newNode(nkExprColonExpr, n.info, @[ var pair = newNode(nkExprColonExpr, n.info, @[
newIdentNode(getIdent"raises", n.info), effects]) newIdentNode(getIdent(specialWords[effectType]), n.info), effects])
if x.kind == nkEmpty: if x.kind == nkEmpty:
x = newNodeI(nkPragma, n.info) x = newNodeI(nkPragma, n.info)
n.sons[pragmasPos] = x n.sons[pragmasPos] = x
x.add(pair) x.add(pair)
proc documentRaises*(n: PNode) =
if n.sons[namePos].kind != nkSym: return
var x = n.sons[pragmasPos]
documentEffect(n, x, wRaises, exceptionEffects)
documentEffect(n, x, wTags, tagEffects)
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 createTag(n: PNode): PNode =
result = newNodeIT(nkType, n.info, sysTypeFromName"TEffect")
proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
let pragma = s.ast.sons[pragmasPos]
let spec = effectSpec(pragma, wRaises)
if not isNil(spec):
mergeEffects(tracked, spec, useLineInfo=false)
else:
addEffect(tracked, createRaise(n))
let tagSpec = effectSpec(pragma, wTags)
if not isNil(tagSpec):
mergeTags(tracked, tagSpec, useLineInfo=false)
else:
addTag(tracked, createTag(n))
proc track(tracked: PEffects, n: PNode) = proc track(tracked: PEffects, n: PNode) =
case n.kind case n.kind
of nkRaiseStmt: of nkRaiseStmt:
n.sons[0].info = n.info n.sons[0].info = n.info
throws(tracked, n.sons[0]) throws(tracked.exc, n.sons[0])
of nkCallKinds: of nkCallKinds:
# p's effects are ours too: # p's effects are ours too:
let a = n.sons[0] let a = n.sons[0]
@ -212,23 +244,16 @@ proc track(tracked: PEffects, n: PNode) =
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 a.kind == nkSym and a.sym.kind == skMethod: if a.kind == nkSym and a.sym.kind == skMethod:
let spec = raisesSpec(a.sym.ast.sons[pragmasPos]) propagateEffects(tracked, n, a.sym)
if not isNil(spec):
mergeEffects(tracked, spec, useLineInfo=false)
else:
addEffect(tracked, createRaise(n))
elif effectList.len == 0: elif effectList.len == 0:
if isForwardedProc(a): if isForwardedProc(a):
let spec = raisesSpec(a.sym.ast.sons[pragmasPos]) propagateEffects(tracked, n, a.sym)
if not isNil(spec):
mergeEffects(tracked, spec, useLineInfo=false)
else:
addEffect(tracked, createRaise(n))
elif isIndirectCall(a): elif isIndirectCall(a):
addEffect(tracked, createRaise(n)) addEffect(tracked, createRaise(n))
addTag(tracked, createTag(n))
else: else:
effectList = effectList.sons[exceptionEffects] mergeEffects(tracked, effectList.sons[exceptionEffects], true)
mergeEffects(tracked, effectList, useLineInfo=true) mergeTags(tracked, effectList.sons[tagEffects], true)
of nkTryStmt: of nkTryStmt:
trackTryStmt(tracked, n) trackTryStmt(tracked, n)
return return
@ -240,7 +265,7 @@ proc track(tracked: PEffects, n: PNode) =
for i in 0 .. <safeLen(n): for i in 0 .. <safeLen(n):
track(tracked, n.sons[i]) track(tracked, n.sons[i])
proc checkRaisesSpec(spec, real: PNode) = proc checkRaisesSpec(spec, real: PNode, msg: string, hints: bool) =
# 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;
# report any unused exception # report any unused exception
var used = initIntSet() var used = initIntSet()
@ -252,41 +277,43 @@ proc checkRaisesSpec(spec, real: PNode) =
break search break search
# XXX call graph analysis would be nice here! # XXX call graph analysis would be nice here!
pushInfoContext(spec.info) pushInfoContext(spec.info)
localError(r.info, errGenerated, "can raise an unlisted exception: " & localError(r.info, errGenerated, msg & typeToString(r.typ))
typeToString(r.typ))
popInfoContext() popInfoContext()
# hint about unnecessarily listed exception types: # hint about unnecessarily listed exception types:
for s in 0 .. <spec.len: if hints:
if not used.contains(s): for s in 0 .. <spec.len:
Message(spec[s].info, hintXDeclaredButNotUsed, renderTree(spec[s])) if not used.contains(s):
Message(spec[s].info, hintXDeclaredButNotUsed, renderTree(spec[s]))
proc checkMethodEffects*(disp, branch: PSym) = proc checkMethodEffects*(disp, branch: PSym) =
## checks for consistent effects for multi methods. ## checks for consistent effects for multi methods.
let spec = raisesSpec(disp.ast.sons[pragmasPos]) let actual = branch.typ.n.sons[0]
if not isNil(spec): if actual.len != effectListLen: return
let actual = branch.typ.n.sons[0]
if actual.len != effectListLen: return let p = disp.ast.sons[pragmasPos]
let real = actual.sons[exceptionEffects] let raisesSpec = effectSpec(p, wRaises)
if not isNil(raisesSpec):
for r in items(real): checkRaisesSpec(raisesSpec, actual.sons[exceptionEffects],
block search: "can raise an unlisted exception: ", hints=off)
for s in 0 .. <spec.len: let tagsSpec = effectSpec(p, wTags)
if inheritanceDiff(r.excType, spec[s].typ) <= 0: if not isNil(tagsSpec):
break search checkRaisesSpec(tagsSpec, actual.sons[tagEffects],
pushInfoContext(branch.info) "can have an unlisted effect: ", hints=off)
localError(r.info, errGenerated, "can raise an unlisted exception: " &
typeToString(r.typ))
popInfoContext()
proc setEffectsForProcType*(t: PType, n: PNode) = proc setEffectsForProcType*(t: PType, n: PNode) =
var effects = t.n.sons[0] var effects = t.n.sons[0]
InternalAssert t.kind == tyProc and effects.kind == nkEffectList InternalAssert t.kind == tyProc and effects.kind == nkEffectList
let spec = raisesSpec(n) let
if not isNil(spec): raisesSpec = effectSpec(n, wRaises)
tagsSpec = effectSpec(n, wTags)
if not isNil(raisesSpec) or not isNil(tagsSpec):
InternalAssert effects.len == 0 InternalAssert effects.len == 0
newSeq(effects.sons, effectListLen) newSeq(effects.sons, effectListLen)
effects.sons[exceptionEffects] = spec if not isNil(raisesSpec):
effects.sons[exceptionEffects] = raisesSpec
if not isNil(tagsSpec):
effects.sons[tagEffects] = tagsSpec
proc trackProc*(s: PSym, body: PNode) = proc trackProc*(s: PSym, body: PNode) =
var effects = s.typ.n.sons[0] var effects = s.typ.n.sons[0]
@ -296,11 +323,24 @@ proc trackProc*(s: PSym, body: PNode) =
if effects.len == effectListLen: return if effects.len == effectListLen: return
newSeq(effects.sons, effectListLen) newSeq(effects.sons, effectListLen)
effects.sons[exceptionEffects] = newNodeI(nkArgList, body.info) effects.sons[exceptionEffects] = newNodeI(nkArgList, body.info)
effects.sons[tagEffects] = newNodeI(nkArgList, body.info)
var t: TEffects var t: TEffects
t.exc = effects.sons[exceptionEffects] t.exc = effects.sons[exceptionEffects]
t.tags = effects.sons[tagEffects]
track(t, body) track(t, body)
let spec = raisesSpec(s.ast.sons[pragmasPos]) let p = s.ast.sons[pragmasPos]
if not isNil(spec): let raisesSpec = effectSpec(p, wRaises)
checkRaisesSpec(spec, t.exc) if not isNil(raisesSpec):
checkRaisesSpec(raisesSpec, t.exc, "can raise an unlisted exception: ",
hints=on)
# after the check, use the formal spec:
effects.sons[exceptionEffects] = raisesSpec
let tagsSpec = effectSpec(p, wTags)
if not isNil(tagsSpec):
checkRaisesSpec(tagsSpec, t.tags, "can have an unlisted effect: ",
hints=on)
# after the check, use the formal spec:
effects.sons[tagEffects] = tagsSpec

View file

@ -1190,6 +1190,16 @@ proc baseOfDistinct*(t: PType): PType =
internalAssert parent != nil internalAssert parent != nil
parent.sons[0] = it.sons[0] parent.sons[0] = it.sons[0]
proc compatibleEffectsAux(se, re: PNode): bool =
if re.isNil: return false
for r in items(re):
block search:
for s in items(se):
if inheritanceDiff(r.typ, s.typ) <= 0:
break search
return false
result = true
proc compatibleEffects*(formal, actual: PType): bool = proc compatibleEffects*(formal, actual: PType): bool =
# for proc type compatibility checking: # for proc type compatibility checking:
assert formal.kind == tyProc and actual.kind == tyProc assert formal.kind == tyProc and actual.kind == tyProc
@ -1197,18 +1207,23 @@ proc compatibleEffects*(formal, actual: PType): bool =
InternalAssert actual.n.sons[0].kind == nkEffectList InternalAssert actual.n.sons[0].kind == nkEffectList
var spec = formal.n.sons[0] var spec = formal.n.sons[0]
# if 'spec.sons[0].kind == nkArgList' it is no formal type really, but a if spec.len != 0:
# 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] var real = actual.n.sons[0]
if real.len == 0:
# we don't know anything about 'real' ... let se = spec.sons[exceptionEffects]
return false # if 'se.kind == nkArgList' it is no formal type really, but a
for r in items(real): # computed effect and as such no spec:
block search: # 'r.msgHandler = if isNil(msgHandler): defaultMsgHandler else: msgHandler'
for s in items(spec): if not IsNil(se) and se.kind != nkArgList:
if inheritanceDiff(r.typ, s.typ) <= 0: # spec requires some exception or tag, but we don't know anything:
break search if real.len == 0: return false
return false result = compatibleEffectsAux(se, real.sons[exceptionEffects])
if not result: return
let st = spec.sons[tagEffects]
if not isNil(st) and st.kind != nkArgList:
# spec requires some exception or tag, but we don't know anything:
if real.len == 0: return false
result = compatibleEffectsAux(st, real.sons[tagEffects])
if not result: return
result = true result = true

View file

@ -52,7 +52,7 @@ type
wBoundchecks, wOverflowchecks, wNilchecks, wBoundchecks, wOverflowchecks, wNilchecks,
wFloatchecks, wNanChecks, wInfChecks, wFloatchecks, wNanChecks, wInfChecks,
wAssertions, wPatterns, wWarnings, wAssertions, wPatterns, wWarnings,
wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wTags,
wDeadCodeElim, wSafecode, wDeadCodeElim, wSafecode,
wPragma, wPragma,
wCompileTime, wNoInit, wCompileTime, wNoInit,
@ -94,7 +94,7 @@ const
cppNimSharedKeywords* = { cppNimSharedKeywords* = {
wAsm, wBreak, wCase, wConst, wContinue, wDo, wElse, wEnum, wExport, wAsm, wBreak, wCase, wConst, wContinue, wDo, wElse, wEnum, wExport,
wFor, wIf, wReturn, wStatic, wTemplate, wTry, wWhile } wFor, wIf, wReturn, wStatic, wTemplate, wTry, wWhile}
specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["", specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["",
@ -133,7 +133,7 @@ const
"floatchecks", "nanchecks", "infchecks", "floatchecks", "nanchecks", "infchecks",
"assertions", "patterns", "warnings", "hints", "assertions", "patterns", "warnings", "hints",
"optimization", "raises", "writes", "reads", "size", "effects", "optimization", "raises", "writes", "reads", "size", "effects", "tags",
"deadcodeelim", "safecode", "deadcodeelim", "safecode",
"pragma", "pragma",
"compiletime", "noinit", "compiletime", "noinit",

View file

@ -2850,11 +2850,9 @@ possibly raised exceptions; the algorithm operates on ``p``'s call graph:
Tag tracking Tag tracking
~~~~~~~~~~~~ ~~~~~~~~~~~~
**Note**: Tag tracking is not yet implemented!
The exception tracking is part of Nimrod's `effect system`:idx:. Raising an The exception tracking is part of Nimrod's `effect system`:idx:. Raising an
exception is an *effect*. Other effects can also be defined. A user defined exception is an *effect*. Other effects can also be defined. A user defined
effect is a means to *tag* a routine and perform checks against this tag: effect is a means to *tag* a routine and to perform checks against this tag:
.. code-block:: nimrod .. code-block:: nimrod
type IO = object ## input/output effect type IO = object ## input/output effect
@ -3093,8 +3091,6 @@ To be written.
Return Type Inference Return Type Inference
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~
**Note**: ``auto`` is not yet implemented.
If a type class is used as the return type of a proc and it won't be bound to If a type class is used as the return type of a proc and it won't be bound to
a concrete type by some of the proc params, Nimrod will infer the return type a concrete type by some of the proc params, Nimrod will infer the return type
from the proc body. This is usually used with the ``auto`` type class: from the proc body. This is usually used with the ``auto`` type class:

View file

@ -209,6 +209,16 @@ type
## objects that have no ancestor are allowed. ## objects that have no ancestor are allowed.
PObject* = ref TObject ## reference to TObject PObject* = ref TObject ## reference to TObject
TEffect* {.compilerproc.} = object of TObject ## \
## base effect class; each effect should
## inherit from `TEffect` unless you know what
## you doing.
FTime* = object of TEffect ## Time effect.
FIO* = object of TEffect ## IO effect.
FReadIO* = object of FIO ## Effect describing a read IO operation.
FWriteIO* = object of FIO ## Effect describing a write IO operation.
FExecIO* = object of FIO ## Effect describing an executing IO operation.
E_Base* {.compilerproc.} = object of TObject ## base exception class; E_Base* {.compilerproc.} = object of TObject ## base exception class;
## each exception has to ## each exception has to
## inherit from `E_Base`. ## inherit from `E_Base`.

View file

@ -0,0 +1,19 @@
discard """
line: 18
errormsg: "type mismatch"
"""
type
TObj = object {.pure, inheritable.}
TObjB = object of TObj
a, b, c: string
fn: proc (): int {.tags: [].}
EIO2 = ref object of EIO
proc raiser(): int {.tags: [TObj].} =
writeln stdout, "arg"
var o: TObjB
o.fn = raiser

View file

@ -0,0 +1,24 @@
discard """
line: 23
errormsg: "type mismatch"
"""
type
TObj = object {.pure, inheritable.}
TObjB = object of TObj
a, b, c: string
fn: proc (): int {.tags: [FReadIO].}
EIO2 = ref object of EIO
proc q() {.tags: [FIO].} =
nil
proc raiser(): int =
writeln stdout, "arg"
if true:
q()
var o: TObjB
o.fn = raiser

View file

@ -38,13 +38,13 @@ Language Additions
- Added a ``mixin`` declaration to affect symbol binding rules in generics. - Added a ``mixin`` declaration to affect symbol binding rules in generics.
- Exception tracking has been added and the ``doc2`` command annotates possible - Exception tracking has been added and the ``doc2`` command annotates possible
exceptions for you. exceptions for you.
- User defined effects ("tags") tracking has been added and the ``doc2``
command annotates possible tags for you.
2012-09-23 Version 0.9.0 released 2012-09-23 Version 0.9.0 released
================================= =================================
Version 0.9.0 has been released! Get it `here <download.html>`_.
Summary Summary
------- -------