mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-01 02:42:05 +00:00
sempass2 compiles again
This commit is contained in:
@@ -280,7 +280,7 @@ errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3",
|
||||
errWrongNumberOfArguments: "wrong number of arguments",
|
||||
errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'",
|
||||
errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters",
|
||||
errXCannotBePassedToProcVar: "'$1' cannot be passed to a procvar",
|
||||
errXCannotBePassedToProcVar: ,
|
||||
errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1",
|
||||
errImplOfXNotAllowed: "implementation of '$1' is not allowed",
|
||||
errImplOfXexpected: ,
|
||||
|
||||
@@ -402,8 +402,8 @@ proc usefulFact(n: PNode; o: Operators): PNode =
|
||||
|
||||
type
|
||||
TModel* = object
|
||||
s: seq[PNode] # the "knowledge base"
|
||||
o: Operators
|
||||
s*: seq[PNode] # the "knowledge base"
|
||||
o*: Operators
|
||||
|
||||
proc addFact*(m: var TModel, nn: PNode) =
|
||||
let n = usefulFact(nn, m.o)
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
|
||||
import
|
||||
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
|
||||
wordrecg, strutils, options, guards, writetracking, configuration
|
||||
wordrecg, strutils, options, guards, writetracking, configuration,
|
||||
modulegraphs
|
||||
|
||||
when defined(useDfa):
|
||||
import dfa
|
||||
@@ -53,6 +54,7 @@ type
|
||||
gcUnsafe, isRecursive, isToplevel, hasSideEffect, inEnforcedGcSafe: bool
|
||||
maxLockLevel, currLockLevel: TLockLevel
|
||||
config: ConfigRef
|
||||
graph: ModuleGraph
|
||||
PEffects = var TEffects
|
||||
|
||||
proc `<`(a, b: TLockLevel): bool {.borrow.}
|
||||
@@ -257,32 +259,29 @@ proc addToIntersection(inter: var TIntersection, s: int) =
|
||||
proc throws(tracked, n: PNode) =
|
||||
if n.typ == nil or n.typ.kind != tyError: tracked.add n
|
||||
|
||||
proc getEbase(g: ModuleGraph): PType =
|
||||
result = g.sysTypeFromName"Exception"
|
||||
proc getEbase(g: ModuleGraph; info: TLineInfo): PType =
|
||||
result = g.sysTypeFromName(info, "Exception")
|
||||
|
||||
proc excType(n: PNode): PType =
|
||||
proc excType(g: ModuleGraph; n: PNode): PType =
|
||||
# reraise is like raising E_Base:
|
||||
let t = if n.kind == nkEmpty or n.typ.isNil: getEbase() else: n.typ
|
||||
let t = if n.kind == nkEmpty or n.typ.isNil: getEbase(g, n.info) else: n.typ
|
||||
result = skipTypes(t, skipPtrs)
|
||||
|
||||
proc createRaise(n: PNode): PNode =
|
||||
proc createRaise(g: ModuleGraph; n: PNode): PNode =
|
||||
result = newNode(nkType)
|
||||
result.typ = getEbase()
|
||||
result.typ = getEbase(g, n.info)
|
||||
if not n.isNil: result.info = n.info
|
||||
|
||||
proc createTag(n: PNode): PNode =
|
||||
proc createTag(g: ModuleGraph; n: PNode): PNode =
|
||||
result = newNode(nkType)
|
||||
if getCompilerProc("RootEffect") != nil:
|
||||
result.typ = sysTypeFromName"RootEffect"
|
||||
else:
|
||||
result.typ = sysTypeFromName"TEffect"
|
||||
result.typ = g.sysTypeFromName(n.info, "RootEffect")
|
||||
if not n.isNil: result.info = n.info
|
||||
|
||||
proc addEffect(a: PEffects, e: PNode, useLineInfo=true) =
|
||||
assert e.kind != nkRaiseStmt
|
||||
var aa = a.exc
|
||||
for i in a.bottom ..< aa.len:
|
||||
if sameType(aa[i].excType, e.excType):
|
||||
if sameType(a.graph.excType(aa[i]), a.graph.excType(e)):
|
||||
if not useLineInfo or gCmd == cmdDoc: return
|
||||
elif aa[i].info == e.info: return
|
||||
throws(a.exc, e)
|
||||
@@ -297,19 +296,19 @@ proc addTag(a: PEffects, e: PNode, useLineInfo=true) =
|
||||
|
||||
proc mergeEffects(a: PEffects, b, comesFrom: PNode) =
|
||||
if b.isNil:
|
||||
addEffect(a, createRaise(comesFrom))
|
||||
addEffect(a, createRaise(a.graph, comesFrom))
|
||||
else:
|
||||
for effect in items(b): addEffect(a, effect, useLineInfo=comesFrom != nil)
|
||||
|
||||
proc mergeTags(a: PEffects, b, comesFrom: PNode) =
|
||||
if b.isNil:
|
||||
addTag(a, createTag(comesFrom))
|
||||
addTag(a, createTag(a.graph, comesFrom))
|
||||
else:
|
||||
for effect in items(b): addTag(a, effect, useLineInfo=comesFrom != nil)
|
||||
|
||||
proc listEffects(a: PEffects) =
|
||||
for e in items(a.exc): message(e.info, hintUser, typeToString(e.typ))
|
||||
for e in items(a.tags): message(e.info, hintUser, typeToString(e.typ))
|
||||
for e in items(a.exc): message(a.config, e.info, hintUser, typeToString(e.typ))
|
||||
for e in items(a.tags): message(a.config, e.info, hintUser, typeToString(e.typ))
|
||||
#if a.maxLockLevel != 0:
|
||||
# message(e.info, hintUser, "lockLevel: " & a.maxLockLevel)
|
||||
|
||||
@@ -319,7 +318,7 @@ proc catches(tracked: PEffects, e: PType) =
|
||||
var i = tracked.bottom
|
||||
while i < L:
|
||||
# r supertype of e?
|
||||
if safeInheritanceDiff(tracked.exc[i].excType, e) <= 0:
|
||||
if safeInheritanceDiff(tracked.graph.excType(tracked.exc[i]), e) <= 0:
|
||||
tracked.exc.sons[i] = tracked.exc.sons[L-1]
|
||||
dec L
|
||||
else:
|
||||
@@ -488,7 +487,7 @@ proc mergeLockLevels(tracked: PEffects, n: PNode, lockLevel: TLockLevel) =
|
||||
if lockLevel >= tracked.currLockLevel:
|
||||
# if in lock section:
|
||||
if tracked.currLockLevel > 0.TLockLevel:
|
||||
localError n.info, errGenerated,
|
||||
localError tracked.config, n.info, errGenerated,
|
||||
"expected lock level < " & $tracked.currLockLevel &
|
||||
" but got lock level " & $lockLevel
|
||||
tracked.maxLockLevel = max(tracked.maxLockLevel, lockLevel)
|
||||
@@ -502,22 +501,22 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
|
||||
mergeTags(tracked, tagSpec, n)
|
||||
|
||||
if notGcSafe(s.typ) and sfImportc notin s.flags:
|
||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
|
||||
markGcUnsafe(tracked, s)
|
||||
if tfNoSideEffect notin s.typ.flags:
|
||||
markSideEffect(tracked, s)
|
||||
mergeLockLevels(tracked, n, s.getLockLevel)
|
||||
|
||||
proc procVarcheck(n: PNode) =
|
||||
proc procVarcheck(n: PNode; conf: ConfigRef) =
|
||||
if n.kind in nkSymChoices:
|
||||
for x in n: procVarCheck(x)
|
||||
for x in n: procVarCheck(x, conf)
|
||||
elif n.kind == nkSym and n.sym.magic != mNone and n.sym.kind in routineKinds:
|
||||
localError(n.info, errXCannotBePassedToProcVar, n.sym.name.s)
|
||||
localError(conf, n.info, "'$1' cannot be passed to a procvar" % n.sym.name.s)
|
||||
|
||||
proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
let n = n.skipConv
|
||||
if paramType.isNil or paramType.kind != tyTypeDesc:
|
||||
procVarcheck skipConvAndClosure(n)
|
||||
procVarcheck skipConvAndClosure(n), tracked.config
|
||||
#elif n.kind in nkSymChoices:
|
||||
# echo "came here"
|
||||
let paramType = paramType.skipTypesOrNil(abstractInst)
|
||||
@@ -533,15 +532,16 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
return
|
||||
case impliesNotNil(tracked.guards, n)
|
||||
of impUnknown:
|
||||
message(n.info, errGenerated,
|
||||
message(tracked.config, n.info, errGenerated,
|
||||
"cannot prove '$1' is not nil" % n.renderTree)
|
||||
of impNo:
|
||||
message(n.info, errGenerated, "'$1' is provably nil" % n.renderTree)
|
||||
message(tracked.config, n.info, errGenerated,
|
||||
"'$1' is provably nil" % n.renderTree)
|
||||
of impYes: discard
|
||||
|
||||
proc assumeTheWorst(tracked: PEffects; n: PNode; op: PType) =
|
||||
addEffect(tracked, createRaise(n))
|
||||
addTag(tracked, createTag(n))
|
||||
addEffect(tracked, createRaise(tracked.graph, n))
|
||||
addTag(tracked, createTag(tracked.graph, n))
|
||||
let lockLevel = if op.lockLevel == UnspecifiedLockLevel: UnknownLockLevel
|
||||
else: op.lockLevel
|
||||
#if lockLevel == UnknownLockLevel:
|
||||
@@ -556,7 +556,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
let a = skipConvAndClosure(n)
|
||||
let op = a.typ
|
||||
if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit:
|
||||
internalAssert op.n.sons[0].kind == nkEffectList
|
||||
internalAssert tracked.config, op.n.sons[0].kind == nkEffectList
|
||||
var effectList = op.n.sons[0]
|
||||
let s = n.skipConv
|
||||
if s.kind == nkSym and s.sym.kind in routineKinds:
|
||||
@@ -571,7 +571,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
assumeTheWorst(tracked, n, op)
|
||||
# assume GcUnsafe unless in its type; 'forward' does not matter:
|
||||
if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
|
||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
|
||||
markGcUnsafe(tracked, a)
|
||||
elif tfNoSideEffect notin op.flags and not isOwnedProcVar(a, tracked.owner):
|
||||
markSideEffect(tracked, a)
|
||||
@@ -579,7 +579,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
|
||||
mergeTags(tracked, effectList.sons[tagEffects], n)
|
||||
if notGcSafe(op):
|
||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
|
||||
markGcUnsafe(tracked, a)
|
||||
elif tfNoSideEffect notin op.flags:
|
||||
markSideEffect(tracked, a)
|
||||
@@ -591,7 +591,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
# XXX figure out why this can be a non tyProc here. See httpclient.nim for an
|
||||
# example that triggers it.
|
||||
if argtype.kind == tyProc and notGcSafe(argtype) and not tracked.inEnforcedGcSafe:
|
||||
localError(n.info, $n & " is not GC safe")
|
||||
localError(tracked.config, n.info, $n & " is not GC safe")
|
||||
notNilCheck(tracked, n, paramType)
|
||||
|
||||
proc breaksBlock(n: PNode): bool =
|
||||
@@ -607,18 +607,18 @@ proc breaksBlock(n: PNode): bool =
|
||||
proc trackCase(tracked: PEffects, n: PNode) =
|
||||
track(tracked, n.sons[0])
|
||||
let oldState = tracked.init.len
|
||||
let oldFacts = tracked.guards.len
|
||||
let oldFacts = tracked.guards.s.len
|
||||
let stringCase = skipTypes(n.sons[0].typ,
|
||||
abstractVarRange-{tyTypeDesc}).kind in {tyFloat..tyFloat128, tyString}
|
||||
let interesting = not stringCase and interestingCaseExpr(n.sons[0]) and
|
||||
warnProveField in gNotes
|
||||
warnProveField in tracked.config.notes
|
||||
var inter: TIntersection = @[]
|
||||
var toCover = 0
|
||||
for i in 1..<n.len:
|
||||
let branch = n.sons[i]
|
||||
setLen(tracked.init, oldState)
|
||||
if interesting:
|
||||
setLen(tracked.guards, oldFacts)
|
||||
setLen(tracked.guards.s, oldFacts)
|
||||
addCaseBranchFacts(tracked.guards, n, i)
|
||||
for i in 0 ..< branch.len:
|
||||
track(tracked, branch.sons[i])
|
||||
@@ -631,11 +631,11 @@ proc trackCase(tracked: PEffects, n: PNode) =
|
||||
for id, count in items(inter):
|
||||
if count >= toCover: tracked.init.add id
|
||||
# else we can't merge
|
||||
setLen(tracked.guards, oldFacts)
|
||||
setLen(tracked.guards.s, oldFacts)
|
||||
|
||||
proc trackIf(tracked: PEffects, n: PNode) =
|
||||
track(tracked, n.sons[0].sons[0])
|
||||
let oldFacts = tracked.guards.len
|
||||
let oldFacts = tracked.guards.s.len
|
||||
addFact(tracked.guards, n.sons[0].sons[0])
|
||||
let oldState = tracked.init.len
|
||||
|
||||
@@ -648,7 +648,7 @@ proc trackIf(tracked: PEffects, n: PNode) =
|
||||
|
||||
for i in 1..<n.len:
|
||||
let branch = n.sons[i]
|
||||
setLen(tracked.guards, oldFacts)
|
||||
setLen(tracked.guards.s, oldFacts)
|
||||
for j in 0..i-1:
|
||||
addFactNeg(tracked.guards, n.sons[j].sons[0])
|
||||
if branch.len > 1:
|
||||
@@ -664,7 +664,7 @@ proc trackIf(tracked: PEffects, n: PNode) =
|
||||
for id, count in items(inter):
|
||||
if count >= toCover: tracked.init.add id
|
||||
# else we can't merge as it is not exhaustive
|
||||
setLen(tracked.guards, oldFacts)
|
||||
setLen(tracked.guards.s, oldFacts)
|
||||
|
||||
proc trackBlock(tracked: PEffects, n: PNode) =
|
||||
if n.kind in {nkStmtList, nkStmtListExpr}:
|
||||
@@ -692,7 +692,7 @@ proc paramType(op: PType, i: int): PType =
|
||||
proc cstringCheck(tracked: PEffects; n: PNode) =
|
||||
if n.sons[0].typ.kind == tyCString and (let a = skipConv(n[1]);
|
||||
a.typ.kind == tyString and a.kind notin {nkStrLit..nkTripleStrLit}):
|
||||
message(n.info, warnUnsafeCode, renderTree(n))
|
||||
message(tracked.config, n.info, warnUnsafeCode, renderTree(n))
|
||||
|
||||
proc track(tracked: PEffects, n: PNode) =
|
||||
case n.kind
|
||||
@@ -734,7 +734,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
if notGcSafe(op) and not importedFromC(a):
|
||||
# and it's not a recursive call:
|
||||
if not (a.kind == nkSym and a.sym == tracked.owner):
|
||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
|
||||
markGcUnsafe(tracked, a)
|
||||
if tfNoSideEffect notin op.flags and not importedFromC(a):
|
||||
# and it's not a recursive call:
|
||||
@@ -752,7 +752,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
# var s: seq[notnil]; newSeq(s, 0) is a special case!
|
||||
discard
|
||||
else:
|
||||
message(arg.info, warnProveInit, $arg)
|
||||
message(tracked.config, arg.info, warnProveInit, $arg)
|
||||
for i in 0 ..< safeLen(n):
|
||||
track(tracked, n.sons[i])
|
||||
of nkDotExpr:
|
||||
@@ -760,7 +760,8 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
for i in 0 ..< len(n): track(tracked, n.sons[i])
|
||||
of nkCheckedFieldExpr:
|
||||
track(tracked, n.sons[0])
|
||||
if warnProveField in gNotes: checkFieldAccess(tracked.guards, n)
|
||||
if warnProveField in tracked.config.notes:
|
||||
checkFieldAccess(tracked.guards, n, tracked.config)
|
||||
of nkTryStmt: trackTryStmt(tracked, n)
|
||||
of nkPragma: trackPragmaStmt(tracked, n)
|
||||
of nkAsgn, nkFastAsgn:
|
||||
@@ -797,11 +798,11 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
else:
|
||||
# loop may never execute:
|
||||
let oldState = tracked.init.len
|
||||
let oldFacts = tracked.guards.len
|
||||
let oldFacts = tracked.guards.s.len
|
||||
addFact(tracked.guards, n.sons[0])
|
||||
track(tracked, n.sons[1])
|
||||
setLen(tracked.init, oldState)
|
||||
setLen(tracked.guards, oldFacts)
|
||||
setLen(tracked.guards.s, oldFacts)
|
||||
of nkForStmt, nkParForStmt:
|
||||
# we are very conservative here and assume the loop is never executed:
|
||||
let oldState = tracked.init.len
|
||||
@@ -810,13 +811,13 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
setLen(tracked.init, oldState)
|
||||
of nkObjConstr:
|
||||
when false: track(tracked, n.sons[0])
|
||||
let oldFacts = tracked.guards.len
|
||||
let oldFacts = tracked.guards.s.len
|
||||
for i in 1 ..< len(n):
|
||||
let x = n.sons[i]
|
||||
track(tracked, x)
|
||||
if x.sons[0].kind == nkSym and sfDiscriminant in x.sons[0].sym.flags:
|
||||
addDiscriminantFact(tracked.guards, x)
|
||||
setLen(tracked.guards, oldFacts)
|
||||
setLen(tracked.guards.s, oldFacts)
|
||||
of nkPragmaBlock:
|
||||
let pragmaList = n.sons[0]
|
||||
let oldLocked = tracked.locked.len
|
||||
@@ -843,31 +844,31 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
else:
|
||||
for i in 0 ..< safeLen(n): track(tracked, n.sons[i])
|
||||
|
||||
proc subtypeRelation(spec, real: PNode): bool =
|
||||
result = safeInheritanceDiff(real.excType, spec.typ) <= 0
|
||||
proc subtypeRelation(g: ModuleGraph; spec, real: PNode): bool =
|
||||
result = safeInheritanceDiff(g.excType(real), spec.typ) <= 0
|
||||
|
||||
proc checkRaisesSpec(spec, real: PNode, msg: string, hints: bool;
|
||||
effectPredicate: proc (a, b: PNode): bool {.nimcall.}) =
|
||||
proc checkRaisesSpec(g: ModuleGraph; spec, real: PNode, msg: string, hints: bool;
|
||||
effectPredicate: proc (g: ModuleGraph; a, b: PNode): bool {.nimcall.}) =
|
||||
# check that any real exception is listed in 'spec'; mark those as used;
|
||||
# report any unused exception
|
||||
var used = initIntSet()
|
||||
for r in items(real):
|
||||
block search:
|
||||
for s in 0 ..< spec.len:
|
||||
if effectPredicate(spec[s], r):
|
||||
if effectPredicate(g, spec[s], r):
|
||||
used.incl(s)
|
||||
break search
|
||||
# XXX call graph analysis would be nice here!
|
||||
pushInfoContext(spec.info)
|
||||
localError(r.info, errGenerated, msg & typeToString(r.typ))
|
||||
localError(g.config, r.info, errGenerated, msg & typeToString(r.typ))
|
||||
popInfoContext()
|
||||
# hint about unnecessarily listed exception types:
|
||||
if hints:
|
||||
for s in 0 ..< spec.len:
|
||||
if not used.contains(s):
|
||||
message(spec[s].info, hintXDeclaredButNotUsed, renderTree(spec[s]))
|
||||
message(g.config, spec[s].info, hintXDeclaredButNotUsed, renderTree(spec[s]))
|
||||
|
||||
proc checkMethodEffects*(disp, branch: PSym) =
|
||||
proc checkMethodEffects*(g: ModuleGraph; disp, branch: PSym) =
|
||||
## checks for consistent effects for multi methods.
|
||||
let actual = branch.typ.n.sons[0]
|
||||
if actual.len != effectListLen: return
|
||||
@@ -875,42 +876,42 @@ proc checkMethodEffects*(disp, branch: PSym) =
|
||||
let p = disp.ast.sons[pragmasPos]
|
||||
let raisesSpec = effectSpec(p, wRaises)
|
||||
if not isNil(raisesSpec):
|
||||
checkRaisesSpec(raisesSpec, actual.sons[exceptionEffects],
|
||||
checkRaisesSpec(g, raisesSpec, actual.sons[exceptionEffects],
|
||||
"can raise an unlisted exception: ", hints=off, subtypeRelation)
|
||||
let tagsSpec = effectSpec(p, wTags)
|
||||
if not isNil(tagsSpec):
|
||||
checkRaisesSpec(tagsSpec, actual.sons[tagEffects],
|
||||
checkRaisesSpec(g, tagsSpec, actual.sons[tagEffects],
|
||||
"can have an unlisted effect: ", hints=off, subtypeRelation)
|
||||
if sfThread in disp.flags and notGcSafe(branch.typ):
|
||||
localError(branch.info, "base method is GC-safe, but '$1' is not" %
|
||||
localError(g.config, branch.info, "base method is GC-safe, but '$1' is not" %
|
||||
branch.name.s)
|
||||
if branch.typ.lockLevel > disp.typ.lockLevel:
|
||||
when true:
|
||||
message(branch.info, warnLockLevel,
|
||||
message(g.config, branch.info, warnLockLevel,
|
||||
"base method has lock level $1, but dispatcher has $2" %
|
||||
[$branch.typ.lockLevel, $disp.typ.lockLevel])
|
||||
else:
|
||||
# XXX make this an error after bigbreak has been released:
|
||||
localError(branch.info,
|
||||
localError(g.config, branch.info,
|
||||
"base method has lock level $1, but dispatcher has $2" %
|
||||
[$branch.typ.lockLevel, $disp.typ.lockLevel])
|
||||
|
||||
proc setEffectsForProcType*(t: PType, n: PNode) =
|
||||
proc setEffectsForProcType*(g: ModuleGraph; t: PType, n: PNode) =
|
||||
var effects = t.n.sons[0]
|
||||
internalAssert t.kind == tyProc and effects.kind == nkEffectList
|
||||
if t.kind != tyProc or effects.kind != nkEffectList: return
|
||||
|
||||
let
|
||||
raisesSpec = effectSpec(n, wRaises)
|
||||
tagsSpec = effectSpec(n, wTags)
|
||||
if not isNil(raisesSpec) or not isNil(tagsSpec):
|
||||
internalAssert effects.len == 0
|
||||
internalAssert g.config, effects.len == 0
|
||||
newSeq(effects.sons, effectListLen)
|
||||
if not isNil(raisesSpec):
|
||||
effects.sons[exceptionEffects] = raisesSpec
|
||||
if not isNil(tagsSpec):
|
||||
effects.sons[tagEffects] = tagsSpec
|
||||
|
||||
proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
|
||||
proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; t: var TEffects) =
|
||||
newSeq(effects.sons, effectListLen)
|
||||
effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info)
|
||||
effects.sons[tagEffects] = newNodeI(nkArgList, s.info)
|
||||
@@ -921,36 +922,39 @@ proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
|
||||
t.tags = effects.sons[tagEffects]
|
||||
t.owner = s
|
||||
t.init = @[]
|
||||
t.guards = @[]
|
||||
t.guards.s = @[]
|
||||
t.guards.o = initOperators(g)
|
||||
t.locked = @[]
|
||||
t.graph = g
|
||||
t.config = g.config
|
||||
|
||||
proc trackProc*(s: PSym, body: PNode) =
|
||||
proc trackProc*(g: ModuleGraph; s: PSym, body: PNode) =
|
||||
var effects = s.typ.n.sons[0]
|
||||
internalAssert effects.kind == nkEffectList
|
||||
if effects.kind != nkEffectList: return
|
||||
# effects already computed?
|
||||
if sfForward in s.flags: return
|
||||
if effects.len == effectListLen: return
|
||||
|
||||
var t: TEffects
|
||||
initEffects(effects, s, t)
|
||||
initEffects(g, effects, s, t)
|
||||
track(t, body)
|
||||
if not isEmptyType(s.typ.sons[0]) and
|
||||
{tfNeedsInit, tfNotNil} * s.typ.sons[0].flags != {} and
|
||||
s.kind in {skProc, skFunc, skConverter, skMethod}:
|
||||
var res = s.ast.sons[resultPos].sym # get result symbol
|
||||
if res.id notin t.init:
|
||||
message(body.info, warnProveInit, "result")
|
||||
message(g.config, body.info, warnProveInit, "result")
|
||||
let p = s.ast.sons[pragmasPos]
|
||||
let raisesSpec = effectSpec(p, wRaises)
|
||||
if not isNil(raisesSpec):
|
||||
checkRaisesSpec(raisesSpec, t.exc, "can raise an unlisted exception: ",
|
||||
checkRaisesSpec(g, raisesSpec, t.exc, "can raise an unlisted exception: ",
|
||||
hints=on, subtypeRelation)
|
||||
# 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: ",
|
||||
checkRaisesSpec(g, tagsSpec, t.tags, "can have an unlisted effect: ",
|
||||
hints=off, subtypeRelation)
|
||||
# after the check, use the formal spec:
|
||||
effects.sons[tagEffects] = tagsSpec
|
||||
@@ -958,15 +962,15 @@ proc trackProc*(s: PSym, body: PNode) =
|
||||
if sfThread in s.flags and t.gcUnsafe:
|
||||
if optThreads in gGlobalOptions and optThreadAnalysis in gGlobalOptions:
|
||||
#localError(s.info, "'$1' is not GC-safe" % s.name.s)
|
||||
listGcUnsafety(s, onlyWarning=false)
|
||||
listGcUnsafety(s, onlyWarning=false, g.config)
|
||||
else:
|
||||
listGcUnsafety(s, onlyWarning=true)
|
||||
listGcUnsafety(s, onlyWarning=true, g.config)
|
||||
#localError(s.info, warnGcUnsafe2, s.name.s)
|
||||
if sfNoSideEffect in s.flags and t.hasSideEffect:
|
||||
when false:
|
||||
listGcUnsafety(s, onlyWarning=false)
|
||||
listGcUnsafety(s, onlyWarning=false, g.config)
|
||||
else:
|
||||
localError(s.info, errXhasSideEffects, s.name.s)
|
||||
localError(g.config, s.info, "'$1' has side effects" % s.name.s)
|
||||
if not t.gcUnsafe:
|
||||
s.typ.flags.incl tfGcSafe
|
||||
if not t.hasSideEffect and sfSideEffect notin s.flags:
|
||||
@@ -975,7 +979,7 @@ proc trackProc*(s: PSym, body: PNode) =
|
||||
s.typ.lockLevel = t.maxLockLevel
|
||||
elif t.maxLockLevel > s.typ.lockLevel:
|
||||
#localError(s.info,
|
||||
message(s.info, warnLockLevel,
|
||||
message(g.config, s.info, warnLockLevel,
|
||||
"declared lock level is $1, but real lock level is $2" %
|
||||
[$s.typ.lockLevel, $t.maxLockLevel])
|
||||
when defined(useDfa):
|
||||
@@ -983,12 +987,12 @@ proc trackProc*(s: PSym, body: PNode) =
|
||||
dataflowAnalysis(s, body)
|
||||
when false: trackWrites(s, body)
|
||||
|
||||
proc trackTopLevelStmt*(module: PSym; n: PNode) =
|
||||
proc trackTopLevelStmt*(g: ModuleGraph; module: PSym; n: PNode) =
|
||||
if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, nkFuncDef,
|
||||
nkTypeSection, nkConverterDef, nkMethodDef, nkIteratorDef}:
|
||||
return
|
||||
var effects = newNode(nkEffectList, n.info)
|
||||
var t: TEffects
|
||||
initEffects(effects, module, t)
|
||||
initEffects(g, effects, module, t)
|
||||
t.isToplevel = true
|
||||
track(t, n)
|
||||
|
||||
Reference in New Issue
Block a user