diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2020-10-06 16:47:15 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-06 16:47:15 +0200 |
commit | 92163fa3304e5b6768a50d36a5243639ce4a2f69 (patch) | |
tree | b7aa2705a4772e8f82d61e765ff9158f7b21b441 /compiler/sempass2.nim | |
parent | acd71dd6bb745eb08f81ab489d635951f8edfcfa (diff) | |
download | Nim-92163fa3304e5b6768a50d36a5243639ce4a2f69.tar.gz |
implements https://github.com/nim-lang/RFCs/issues/258 (#15503)
* implements https://github.com/nim-lang/RFCs/issues/258 * don't be too strict with custom pragma blocks * cast pragmas: documentation * added most missing inference query procs to effecttraits.nim
Diffstat (limited to 'compiler/sempass2.nim')
-rw-r--r-- | compiler/sempass2.nim | 108 |
1 files changed, 82 insertions, 26 deletions
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index cda156224..19223b88f 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -325,7 +325,7 @@ proc createTag(g: ModuleGraph; n: PNode): PNode = result.typ = g.sysTypeFromName(n.info, "RootEffect") if not n.isNil: result.info = n.info -proc addEffect(a: PEffects, e, comesFrom: PNode) = +proc addRaiseEffect(a: PEffects, e, comesFrom: PNode) = assert e.kind != nkRaiseStmt var aa = a.exc for i in a.bottom..<aa.len: @@ -345,11 +345,11 @@ proc addTag(a: PEffects, e, comesFrom: PNode) = if sameType(aa[i].typ.skipTypes(skipPtrs), e.typ.skipTypes(skipPtrs)): return throws(a.tags, e, comesFrom) -proc mergeEffects(a: PEffects, b, comesFrom: PNode) = +proc mergeRaises(a: PEffects, b, comesFrom: PNode) = if b.isNil: - addEffect(a, createRaise(a.graph, comesFrom), comesFrom) + addRaiseEffect(a, createRaise(a.graph, comesFrom), comesFrom) else: - for effect in items(b): addEffect(a, effect, comesFrom) + for effect in items(b): addRaiseEffect(a, effect, comesFrom) proc mergeTags(a: PEffects, b, comesFrom: PNode) = if b.isNil: @@ -489,7 +489,7 @@ proc mergeLockLevels(tracked: PEffects, n: PNode, lockLevel: TLockLevel) = proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) = let pragma = s.ast[pragmasPos] let spec = effectSpec(pragma, wRaises) - mergeEffects(tracked, spec, n) + mergeRaises(tracked, spec, n) let tagSpec = effectSpec(pragma, wTags) mergeTags(tracked, tagSpec, n) @@ -535,7 +535,7 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) = of impYes: discard proc assumeTheWorst(tracked: PEffects; n: PNode; op: PType) = - addEffect(tracked, createRaise(tracked.graph, n), nil) + addRaiseEffect(tracked, createRaise(tracked.graph, n), nil) addTag(tracked, createTag(tracked.graph, n), nil) let lockLevel = if op.lockLevel == UnspecifiedLockLevel: UnknownLockLevel else: op.lockLevel @@ -581,7 +581,7 @@ proc trackOperandForIndirectCall(tracked: PEffects, n: PNode, paramType: PType; elif tfNoSideEffect notin op.flags and not isOwnedProcVar(a, tracked.owner): markSideEffect(tracked, a) else: - mergeEffects(tracked, effectList[exceptionEffects], n) + mergeRaises(tracked, effectList[exceptionEffects], n) mergeTags(tracked, effectList[tagEffects], n) if notGcSafe(op): if tracked.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n, tracked.config) @@ -780,7 +780,7 @@ proc trackCall(tracked: PEffects; n: PNode) = assumeTheWorst(tracked, n, op) gcsafeAndSideeffectCheck() else: - mergeEffects(tracked, effectList[exceptionEffects], n) + mergeRaises(tracked, effectList[exceptionEffects], n) mergeTags(tracked, effectList[tagEffects], n) gcsafeAndSideeffectCheck() if a.kind != nkSym or a.sym.magic != mNBindSym: @@ -837,6 +837,64 @@ proc trackCall(tracked: PEffects; n: PNode) = # initVar(tracked, n[i].skipAddr, false) else: discard +type + PragmaBlockContext = object + oldLocked: int + oldLockLevel: TLockLevel + enforcedGcSafety, enforceNoSideEffects: bool + oldExc, oldTags: int + exc, tags: PNode + +proc createBlockContext(tracked: PEffects): PragmaBlockContext = + result = PragmaBlockContext(oldLocked: tracked.locked.len, + oldLockLevel: tracked.currLockLevel, + enforcedGcSafety: false, enforceNoSideEffects: false, + oldExc: tracked.exc.len, oldTags: tracked.tags.len) + +proc applyBlockContext(tracked: PEffects, bc: PragmaBlockContext) = + if bc.enforcedGcSafety: tracked.inEnforcedGcSafe = true + if bc.enforceNoSideEffects: tracked.inEnforcedNoSideEffects = true + +proc unapplyBlockContext(tracked: PEffects; bc: PragmaBlockContext) = + if bc.enforcedGcSafety: tracked.inEnforcedGcSafe = false + if bc.enforceNoSideEffects: tracked.inEnforcedNoSideEffects = false + setLen(tracked.locked, bc.oldLocked) + tracked.currLockLevel = bc.oldLockLevel + if bc.exc != nil: + # beware that 'raises: []' is very different from not saying + # anything about 'raises' in the 'cast' at all. Same applies for 'tags'. + setLen(tracked.exc.sons, bc.oldExc) + for e in bc.exc: + addRaiseEffect(tracked, e, e) + if bc.tags != nil: + setLen(tracked.tags.sons, bc.oldTags) + for t in bc.tags: + addTag(tracked, t, t) + +proc castBlock(tracked: PEffects, pragma: PNode, bc: var PragmaBlockContext) = + case whichPragma(pragma) + of wGcSafe: + bc.enforcedGcSafety = true + of wNoSideEffect: + bc.enforceNoSideEffects = true + of wTags: + let n = pragma[1] + if n.kind in {nkCurly, nkBracket}: + bc.tags = n + else: + bc.tags = newNodeI(nkArgList, pragma.info) + bc.tags.add n + of wRaises: + let n = pragma[1] + if n.kind in {nkCurly, nkBracket}: + bc.exc = n + else: + bc.exc = newNodeI(nkArgList, pragma.info) + bc.exc.add n + else: + localError(tracked.config, pragma.info, + "invalid pragma block: " & $pragma) + proc track(tracked: PEffects, n: PNode) = case n.kind of nkSym: @@ -854,7 +912,7 @@ proc track(tracked: PEffects, n: PNode) = if n[0].kind != nkEmpty: n[0].info = n.info #throws(tracked.exc, n[0]) - addEffect(tracked, n[0], nil) + addRaiseEffect(tracked, n[0], nil) for i in 0..<n.safeLen: track(tracked, n[i]) createTypeBoundOps(tracked, n[0].typ, n.info) @@ -862,7 +920,7 @@ proc track(tracked: PEffects, n: PNode) = # A `raise` with no arguments means we're going to re-raise the exception # being handled or, if outside of an `except` block, a `ReraiseDefect`. # Here we add a `Exception` tag in order to cover both the cases. - addEffect(tracked, createRaise(tracked.graph, n), nil) + addRaiseEffect(tracked, createRaise(tracked.graph, n), nil) of nkCallKinds: trackCall(tracked, n) of nkDotExpr: @@ -1011,26 +1069,24 @@ proc track(tracked: PEffects, n: PNode) = checkForSink(tracked.config, tracked.owner, n[i]) of nkPragmaBlock: let pragmaList = n[0] - let oldLocked = tracked.locked.len - let oldLockLevel = tracked.currLockLevel - var enforcedGcSafety = false - var enforceNoSideEffects = false + var bc = createBlockContext(tracked) for i in 0..<pragmaList.len: let pragma = whichPragma(pragmaList[i]) - if pragma == wLocks: + case pragma + of wLocks: lockLocations(tracked, pragmaList[i]) - elif pragma == wGcSafe: - enforcedGcSafety = true - elif pragma == wNoSideEffect: - enforceNoSideEffects = true - - if enforcedGcSafety: tracked.inEnforcedGcSafe = true - if enforceNoSideEffects: tracked.inEnforcedNoSideEffects = true + of wGcSafe: + bc.enforcedGcSafety = true + of wNoSideEffect: + bc.enforceNoSideEffects = true + of wCast: + castBlock(tracked, pragmaList[i][1], bc) + else: + discard + applyBlockContext(tracked, bc) track(tracked, n.lastSon) - if enforcedGcSafety: tracked.inEnforcedGcSafe = false - if enforceNoSideEffects: tracked.inEnforcedNoSideEffects = false - setLen(tracked.locked, oldLocked) - tracked.currLockLevel = oldLockLevel + unapplyBlockContext(tracked, bc) + of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef: discard |