diff options
-rw-r--r-- | compiler/pragmas.nim | 8 | ||||
-rw-r--r-- | doc/manual/locking.txt | 19 | ||||
-rw-r--r-- | tests/pragmas/tlocks.nim | 13 |
3 files changed, 39 insertions, 1 deletions
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 1fe1c81d2..bcb0461f2 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -582,7 +582,13 @@ proc pragmaLocks(c: PContext, it: PNode): TLockLevel = if it.kind != nkExprColonExpr: invalidPragma(it) 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) if x < 0 or x > MaxLockLevel: localError(it[1].info, "integer must be within 0.." & $MaxLockLevel) diff --git a/doc/manual/locking.txt b/doc/manual/locking.txt index c00efdd91..c1bd5ca46 100644 --- a/doc/manual/locking.txt +++ b/doc/manual/locking.txt @@ -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 relation: ``proc () {.locks: N.}`` is a subtype of ``proc () {.locks: M.}`` 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() diff --git a/tests/pragmas/tlocks.nim b/tests/pragmas/tlocks.nim new file mode 100644 index 000000000..ba66a2dca --- /dev/null +++ b/tests/pragmas/tlocks.nim @@ -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 |