Enabled explicitly unknown lock levels (#5409)
* enabled explicitly unknown lock levels * allowing "unknown" as locks pragma * added test case for locks pragma * updated docs on locks pragma
This commit is contained in:
parent
363b1c0a41
commit
ce4587d7b7
3 changed files with 39 additions and 1 deletions
|
|
@ -582,7 +582,13 @@ proc pragmaLocks(c: PContext, it: PNode): TLockLevel =
|
||||||
if it.kind != nkExprColonExpr:
|
if it.kind != nkExprColonExpr:
|
||||||
invalidPragma(it)
|
invalidPragma(it)
|
||||||
else:
|
else:
|
||||||
if it[1].kind != nkNilLit:
|
case it[1].kind
|
||||||
|
of nkStrLit, nkRStrLit, nkTripleStrLit:
|
||||||
|
if it[1].strVal == "unknown":
|
||||||
|
result = UnknownLockLevel
|
||||||
|
else:
|
||||||
|
localError(it[1].info, "invalid string literal for locks pragma (only allowed string is \"unknown\")")
|
||||||
|
else:
|
||||||
let x = expectIntLit(c, it)
|
let x = expectIntLit(c, it)
|
||||||
if x < 0 or x > MaxLockLevel:
|
if x < 0 or x > MaxLockLevel:
|
||||||
localError(it[1].info, "integer must be within 0.." & $MaxLockLevel)
|
localError(it[1].info, "integer must be within 0.." & $MaxLockLevel)
|
||||||
|
|
|
||||||
|
|
@ -198,3 +198,22 @@ This is essential so that procs can be called within a ``locks`` section:
|
||||||
As usual ``locks`` is an inferred effect and there is a subtype
|
As usual ``locks`` is an inferred effect and there is a subtype
|
||||||
relation: ``proc () {.locks: N.}`` is a subtype of ``proc () {.locks: M.}``
|
relation: ``proc () {.locks: N.}`` is a subtype of ``proc () {.locks: M.}``
|
||||||
iff (M <= N).
|
iff (M <= N).
|
||||||
|
|
||||||
|
The ``locks`` pragma can also take the special value ``"unknown"``. This
|
||||||
|
is useful in the context of dynamic method dispatching. In the following
|
||||||
|
example, the compiler can infer a lock level of 0 for the ``base`` case.
|
||||||
|
However, one of the overloaded methods calls a procvar which is
|
||||||
|
potentially locking. Thus, the lock level of calling ``g.testMethod``
|
||||||
|
cannot be inferred statically, leading to compiler warnings. By using
|
||||||
|
``{.locks: "unknown".}``, the base method can be marked explicitly as
|
||||||
|
having unknown lock level as well:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
type SomeBase* = ref object of RootObj
|
||||||
|
type SomeDerived* = ref object of SomeBase
|
||||||
|
memberProc*: proc ()
|
||||||
|
|
||||||
|
method testMethod(g: SomeBase) {.base, locks: "unknown".} = discard
|
||||||
|
method testMethod(g: SomeDerived) =
|
||||||
|
if g.memberProc != nil:
|
||||||
|
g.memberProc()
|
||||||
|
|
|
||||||
13
tests/pragmas/tlocks.nim
Normal file
13
tests/pragmas/tlocks.nim
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
type SomeBase* = ref object of RootObj
|
||||||
|
type SomeDerived* = ref object of SomeBase
|
||||||
|
memberProc*: proc ()
|
||||||
|
|
||||||
|
method testMethod(g: SomeBase) {.base, locks: "unknown".} = discard
|
||||||
|
method testMethod(g: SomeDerived) =
|
||||||
|
if g.memberProc != nil:
|
||||||
|
g.memberProc()
|
||||||
|
|
||||||
|
# ensure int literals still work
|
||||||
|
proc plain*() {.locks: 0.} =
|
||||||
|
discard
|
||||||
Loading…
Add table
Add a link
Reference in a new issue