summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorringabout <43030857+ringabout@users.noreply.github.com>2022-10-11 15:17:09 +0800
committerGitHub <noreply@github.com>2022-10-11 09:17:09 +0200
commit5602183234f59ece4fd668915da848f0753cbbb9 (patch)
treeb955da8037206560cdc9628d94a3b604bd9ac631
parent75873715546142a6f6f78180abdf1c1ddc0416e5 (diff)
downloadNim-5602183234f59ece4fd668915da848f0753cbbb9.tar.gz
'lock levels' are deprecated, now a noop (#20539)
* 'lock levels' are deprecated, now a noop

* fixes tests
-rw-r--r--changelog.md2
-rw-r--r--compiler/ast.nim12
-rw-r--r--compiler/cgmeth.nim17
-rw-r--r--compiler/ic/ic.nim4
-rw-r--r--compiler/ic/packed_ast.nim1
-rw-r--r--compiler/lineinfos.nim5
-rw-r--r--compiler/main.nim1
-rw-r--r--compiler/pragmas.nim19
-rw-r--r--compiler/semcall.nim3
-rw-r--r--compiler/sempass2.nim78
-rw-r--r--compiler/types.nim31
-rw-r--r--doc/manual_experimental.md99
-rw-r--r--lib/core/macros.nim4
-rw-r--r--lib/pure/net.nim2
-rw-r--r--lib/pure/nimprof.nim8
-rw-r--r--lib/pure/nimtracker.nim2
-rw-r--r--lib/system/cyclebreaker.nim2
-rw-r--r--lib/system/inclrtl.nim2
-rw-r--r--lib/system/memalloc.nim10
-rw-r--r--lib/system/memtracker.nim6
-rw-r--r--lib/system/profiler.nim4
-rw-r--r--lib/system/stacktraces.nim12
-rw-r--r--lib/wrappers/sqlite3.nim2
-rw-r--r--nimsuggest/tests/tdef1.nim4
-rw-r--r--nimsuggest/tests/tdot4.nim2
-rw-r--r--nimsuggest/tests/tinclude.nim2
-rw-r--r--nimsuggest/tests/tsug_template.nim2
-rw-r--r--nimsuggest/tests/tuse.nim8
-rw-r--r--nimsuggest/tests/tv3.nim4
-rw-r--r--nimsuggest/tests/tv3_forward_definition.nim18
-rw-r--r--nimsuggest/tests/tv3_globalSymbols.nim8
-rw-r--r--tests/arc/twrong_sinkinference.nim2
-rw-r--r--tests/bind/tnicerrorforsymchoice.nim2
-rw-r--r--tests/closure/tclosure.nim2
-rw-r--r--tests/closure/tinvalidclosure.nim2
-rw-r--r--tests/closure/tinvalidclosure5.nim2
-rw-r--r--tests/closure/tnested.nim2
-rw-r--r--tests/effects/teffects1.nim2
-rw-r--r--tests/effects/teffects11.nim2
-rw-r--r--tests/effects/teffects19.nim2
-rw-r--r--tests/effects/tgcsafe2.nim2
-rw-r--r--tests/errmsgs/t10489_a.nim2
-rw-r--r--tests/errmsgs/t10489_b.nim2
-rw-r--r--tests/errmsgs/t18886.nim4
-rw-r--r--tests/errmsgs/t2614.nim4
-rw-r--r--tests/errmsgs/t5167_4.nim2
-rw-r--r--tests/errmsgs/tgcsafety.nim6
-rw-r--r--tests/errmsgs/tproc_mismatch.nim25
-rw-r--r--tests/errmsgs/tsigmatch.nim28
-rw-r--r--tests/errmsgs/ttypeAllowed.nim8
-rw-r--r--tests/generics/tprevent_double_bind.nim2
-rw-r--r--tests/lent/t16898.nim2
-rw-r--r--tests/overload/tproc_types_dont_like_subtypes.nim2
-rw-r--r--tests/pragmas/tlocks.nim4
-rw-r--r--tests/statictypes/t9255.nim2
-rw-r--r--tests/stdlib/ttimes.nim4
-rw-r--r--tests/vm/tvmmisc.nim2
57 files changed, 121 insertions, 372 deletions
diff --git a/changelog.md b/changelog.md
index bcb5a6ba7..2e8460b7c 100644
--- a/changelog.md
+++ b/changelog.md
@@ -84,6 +84,8 @@
 - `macros.getImpl` for `const` symbols now returns the full definition node
   (as `nnkConstDef`) rather than the AST of the constant value.
 
+- Lock levels are deprecated, now a noop.
+
 - ORC is now the default memory management strategy. Use
   `--mm:refc` for a transition period.
 
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 2a9556693..c4c183932 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -929,7 +929,6 @@ type
       allUsages*: seq[TLineInfo]
 
   TTypeSeq* = seq[PType]
-  TLockLevel* = distinct int16
 
   TTypeAttachedOp* = enum ## as usual, order is important here
     attachedDestructor,
@@ -963,7 +962,6 @@ type
                               # -1 means that the size is unkwown
     align*: int16             # the type's alignment requirements
     paddingAtEnd*: int16      #
-    lockLevel*: TLockLevel    # lock level as required for deadlock checking
     loc*: TLoc
     typeInst*: PType          # for generic instantiations the tyGenericInst that led to this
                               # type.
@@ -1499,17 +1497,9 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
                   pragmas, exceptions, body]
 
 const
-  UnspecifiedLockLevel* = TLockLevel(-1'i16)
-  MaxLockLevel* = 1000'i16
-  UnknownLockLevel* = TLockLevel(1001'i16)
   AttachedOpToStr*: array[TTypeAttachedOp, string] = [
     "=destroy", "=copy", "=sink", "=trace", "=deepcopy"]
 
-proc `$`*(x: TLockLevel): string =
-  if x.ord == UnspecifiedLockLevel.ord: result = "<unspecified>"
-  elif x.ord == UnknownLockLevel.ord: result = "<unknown>"
-  else: result = $int16(x)
-
 proc `$`*(s: PSym): string =
   if s != nil:
     result = s.name.s & "@" & $s.id
@@ -1519,7 +1509,6 @@ proc `$`*(s: PSym): string =
 proc newType*(kind: TTypeKind, id: ItemId; owner: PSym): PType =
   result = PType(kind: kind, owner: owner, size: defaultSize,
                  align: defaultAlignment, itemId: id,
-                 lockLevel: UnspecifiedLockLevel,
                  uniqueId: id)
   when false:
     if result.itemId.module == 55 and result.itemId.item == 2:
@@ -1544,7 +1533,6 @@ proc assignType*(dest, src: PType) =
   dest.n = src.n
   dest.size = src.size
   dest.align = src.align
-  dest.lockLevel = src.lockLevel
   # this fixes 'type TLock = TSysLock':
   if src.sym != nil:
     if dest.sym != nil:
diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim
index 6b4322a13..23dea1d18 100644
--- a/compiler/cgmeth.nim
+++ b/compiler/cgmeth.nim
@@ -147,23 +147,6 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) =
      disp.ast[resultPos].kind == nkEmpty:
     disp.ast[resultPos] = copyTree(meth.ast[resultPos])
 
-  # The following code works only with lock levels, so we disable
-  # it when they're not available.
-  when declared(TLockLevel):
-    proc `<`(a, b: TLockLevel): bool {.borrow.}
-    proc `==`(a, b: TLockLevel): bool {.borrow.}
-    if disp.typ.lockLevel == UnspecifiedLockLevel:
-      disp.typ.lockLevel = meth.typ.lockLevel
-    elif meth.typ.lockLevel != UnspecifiedLockLevel and
-         meth.typ.lockLevel != disp.typ.lockLevel:
-      message(conf, meth.info, warnLockLevel,
-        "method has lock level $1, but another method has $2" %
-        [$meth.typ.lockLevel, $disp.typ.lockLevel])
-      # XXX The following code silences a duplicate warning in
-      # checkMethodeffects() in sempass2.nim for now.
-      if disp.typ.lockLevel < meth.typ.lockLevel:
-        disp.typ.lockLevel = meth.typ.lockLevel
-
 proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
   var witness: PSym
   for i in 0..<g.methods.len:
diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim
index a745a9d83..36a57f11e 100644
--- a/compiler/ic/ic.nim
+++ b/compiler/ic/ic.nim
@@ -354,7 +354,7 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemI
 
     var p = PackedType(kind: t.kind, flags: t.flags, callConv: t.callConv,
       size: t.size, align: t.align, nonUniqueId: t.itemId.item,
-      paddingAtEnd: t.paddingAtEnd, lockLevel: t.lockLevel)
+      paddingAtEnd: t.paddingAtEnd)
     storeNode(p, t, n)
     p.typeInst = t.typeInst.storeType(c, m)
     for kid in items t.sons:
@@ -900,7 +900,7 @@ proc typeHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
                           t: PackedType; si, item: int32): PType =
   result = PType(itemId: ItemId(module: si, item: t.nonUniqueId), kind: t.kind,
                 flags: t.flags, size: t.size, align: t.align,
-                paddingAtEnd: t.paddingAtEnd, lockLevel: t.lockLevel,
+                paddingAtEnd: t.paddingAtEnd,
                 uniqueId: ItemId(module: si, item: item),
                 callConv: t.callConv)
 
diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim
index c78fe56f5..87b1516fa 100644
--- a/compiler/ic/packed_ast.nim
+++ b/compiler/ic/packed_ast.nim
@@ -84,7 +84,6 @@ type
     size*: BiggestInt
     align*: int16
     paddingAtEnd*: int16
-    lockLevel*: TLockLevel # lock level as required for deadlock checking
     # not serialized: loc*: TLoc because it is backend-specific
     typeInst*: PackedItemId
     nonUniqueId*: int32
diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim
index fcc15606d..c117f5694 100644
--- a/compiler/lineinfos.nim
+++ b/compiler/lineinfos.nim
@@ -68,7 +68,8 @@ type
     warnUnreachableElse = "UnreachableElse", warnUnreachableCode = "UnreachableCode",
     warnStaticIndexCheck = "IndexCheck", warnGcUnsafe = "GcUnsafe", warnGcUnsafe2 = "GcUnsafe2",
     warnUninit = "Uninit", warnGcMem = "GcMem", warnDestructor = "Destructor",
-    warnLockLevel = "LockLevel", warnResultShadowed = "ResultShadowed",
+    warnLockLevel = "LockLevel", # deadcode
+    warnResultShadowed = "ResultShadowed",
     warnInconsistentSpacing = "Spacing",  warnCaseTransition = "CaseTransition",
     warnCycleCreated = "CycleCreated", warnObservableStores = "ObservableStores",
     warnStrictNotNil = "StrictNotNil",
@@ -161,7 +162,7 @@ const
     warnUninit: "use explicit initialization of '$1' for clarity",
     warnGcMem: "'$1' uses GC'ed memory",
     warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.",
-    warnLockLevel: "$1",
+    warnLockLevel: "$1", # deadcode
     warnResultShadowed: "Special variable 'result' is shadowed.",
     warnInconsistentSpacing: "Number of spaces around '$#' is not consistent",
     warnCaseTransition: "Potential object case transition, instantiate new object instead",
diff --git a/compiler/main.nim b/compiler/main.nim
index 171521c7a..71e913d6c 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -294,7 +294,6 @@ proc mainCommand*(graph: ModuleGraph) =
   of cmdDoc0: docLikeCmd commandDoc(cache, conf)
   of cmdDoc:
     docLikeCmd():
-      conf.setNoteDefaults(warnLockLevel, false) # issue #13218
       conf.setNoteDefaults(warnRstRedefinitionOfLabel, false) # issue #13218
         # because currently generates lots of false positives due to conflation
         # of labels links in doc comments, e.g. for random.rand:
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index d4932a877..bcc786703 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -684,23 +684,6 @@ proc pragmaLockStmt(c: PContext; it: PNode) =
       for i in 0..<n.len:
         n[i] = c.semExpr(c, n[i])
 
-proc pragmaLocks(c: PContext, it: PNode): TLockLevel =
-  if it.kind notin nkPragmaCallKinds or it.len != 2:
-    invalidPragma(c, it)
-  else:
-    case it[1].kind
-    of nkStrLit, nkRStrLit, nkTripleStrLit:
-      if it[1].strVal == "unknown":
-        result = UnknownLockLevel
-      else:
-        localError(c.config, 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(c.config, it[1].info, "integer must be within 0.." & $MaxLockLevel)
-      else:
-        result = TLockLevel(x)
-
 proc typeBorrow(c: PContext; sym: PSym, n: PNode) =
   if n.kind in nkPragmaCallKinds and n.len == 2:
     let it = n[1]
@@ -1196,7 +1179,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
       of wLocks:
         if sym == nil: pragmaLockStmt(c, it)
         elif sym.typ == nil: invalidPragma(c, it)
-        else: sym.typ.lockLevel = pragmaLocks(c, it)
+        else: warningDeprecated(c.config, n.info, "'Lock levels' are deprecated, now a noop")
       of wBitsize:
         if sym == nil or sym.kind != skField:
           invalidPragma(c, it)
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index cd009ce69..ed8699a26 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -149,9 +149,6 @@ proc effectProblem(f, a: PType; result: var string; c: PContext) =
       of efTagsUnknown:
         result.add "\n  The `.tags` requirements differ. Annotate the " &
             "proc with {.tags: [].} to get extended error information."
-      of efLockLevelsDiffer:
-        result.add "\n  The `.locks` requirements differ. Annotate the " &
-            "proc with {.locks: 0.} to get extended error information."
       of efEffectsDelayed:
         result.add "\n  The `.effectsOf` annotations differ."
       of efTagsIllegal:
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index a1887b20e..f2da33e8b 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -77,7 +77,6 @@ type
     gcUnsafe, isRecursive, isTopLevel, hasSideEffect, inEnforcedGcSafe: bool
     hasDangerousAssign, isInnerProc: bool
     inEnforcedNoSideEffects: bool
-    maxLockLevel, currLockLevel: TLockLevel
     currOptions: TOptions
     config: ConfigRef
     graph: ModuleGraph
@@ -85,11 +84,6 @@ type
     escapingParams: IntSet
   PEffects = var TEffects
 
-proc `<`(a, b: TLockLevel): bool {.borrow.}
-proc `<=`(a, b: TLockLevel): bool {.borrow.}
-proc `==`(a, b: TLockLevel): bool {.borrow.}
-proc max(a, b: TLockLevel): TLockLevel {.borrow.}
-
 proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) =
   if typ == nil: return
   when false:
@@ -107,33 +101,12 @@ proc isLocalVar(a: PEffects, s: PSym): bool =
   s.typ != nil and (s.kind in {skVar, skResult} or (s.kind == skParam and isOutParam(s.typ))) and
     sfGlobal notin s.flags and s.owner == a.owner
 
-proc getLockLevel(t: PType): TLockLevel =
-  var t = t
-  # tyGenericInst(TLock {tyGenericBody}, tyStatic, tyObject):
-  if t.kind == tyGenericInst and t.len == 3: t = t[1]
-  if t.kind == tyStatic and t.n != nil and t.n.kind in {nkCharLit..nkInt64Lit}:
-    result = t.n.intVal.TLockLevel
-
 proc lockLocations(a: PEffects; pragma: PNode) =
   if pragma.kind != nkExprColonExpr:
     localError(a.config, pragma.info, "locks pragma without argument")
     return
-  var firstLL = TLockLevel(-1'i16)
   for x in pragma[1]:
-    let thisLL = getLockLevel(x.typ)
-    if thisLL != 0.TLockLevel:
-      if thisLL < 0.TLockLevel or thisLL > MaxLockLevel.TLockLevel:
-        localError(a.config, x.info, "invalid lock level: " & $thisLL)
-      elif firstLL < 0.TLockLevel: firstLL = thisLL
-      elif firstLL != thisLL:
-        localError(a.config, x.info,
-          "multi-lock requires the same static lock level for every operand")
-      a.maxLockLevel = max(a.maxLockLevel, firstLL)
     a.locked.add x
-  if firstLL >= 0.TLockLevel and firstLL != a.currLockLevel:
-    if a.currLockLevel > 0.TLockLevel and a.currLockLevel <= firstLL:
-      localError(a.config, pragma.info, "invalid nested locking")
-    a.currLockLevel = firstLL
 
 proc guardGlobal(a: PEffects; n: PNode; guard: PSym) =
   # check whether the corresponding lock is held:
@@ -438,8 +411,6 @@ proc listEffects(a: PEffects) =
   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))
   for e in items(a.forbids): message(a.config, e.info, hintUser, typeToString(e.typ))
-  #if a.maxLockLevel != 0:
-  #  message(e.info, hintUser, "lockLevel: " & a.maxLockLevel)
 
 proc catches(tracked: PEffects, e: PType) =
   let e = skipTypes(e, skipPtrs)
@@ -551,25 +522,6 @@ proc importedFromC(n: PNode): bool =
   # when imported from C, we assume GC-safety.
   result = n.kind == nkSym and sfImportc in n.sym.flags
 
-proc getLockLevel(s: PSym): TLockLevel =
-  result = s.typ.lockLevel
-  if result == UnspecifiedLockLevel:
-    if {sfImportc, sfNoSideEffect} * s.flags != {} or
-       tfNoSideEffect in s.typ.flags:
-      result = 0.TLockLevel
-    else:
-      result = UnknownLockLevel
-      #message(??.config, s.info, warnUser, "FOR THIS " & s.name.s)
-
-proc mergeLockLevels(tracked: PEffects, n: PNode, lockLevel: TLockLevel) =
-  if lockLevel >= tracked.currLockLevel:
-    # if in lock section:
-    if tracked.currLockLevel > 0.TLockLevel:
-      localError tracked.config, n.info, errGenerated,
-        "expected lock level < " & $tracked.currLockLevel &
-        " but got lock level " & $lockLevel
-    tracked.maxLockLevel = max(tracked.maxLockLevel, lockLevel)
-
 proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
   let pragma = s.ast[pragmasPos]
   let spec = effectSpec(pragma, wRaises)
@@ -583,7 +535,6 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
     markGcUnsafe(tracked, s)
   if tfNoSideEffect notin s.typ.flags:
     markSideEffect(tracked, s, n.info)
-  mergeLockLevels(tracked, n, s.getLockLevel)
 
 proc procVarCheck(n: PNode; conf: ConfigRef) =
   if n.kind in nkSymChoices:
@@ -623,11 +574,6 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
 proc assumeTheWorst(tracked: PEffects; n: PNode; op: PType) =
   addRaiseEffect(tracked, createRaise(tracked.graph, n), nil)
   addTag(tracked, createTag(tracked.graph, n), nil)
-  let lockLevel = if op.lockLevel == UnspecifiedLockLevel: UnknownLockLevel
-                  else: op.lockLevel
-  #if lockLevel == UnknownLockLevel:
-  #  message(??.config, n.info, warnUser, "had to assume the worst here")
-  mergeLockLevels(tracked, n, lockLevel)
 
 proc isOwnedProcVar(tracked: PEffects; n: PNode): bool =
   # XXX prove the soundness of this effect system rule
@@ -885,10 +831,9 @@ proc trackCall(tracked: PEffects; n: PNode) =
       if a.kind == nkSym:
         if a.sym == tracked.owner: tracked.isRecursive = true
         # even for recursive calls we need to check the lock levels (!):
-        mergeLockLevels(tracked, n, a.sym.getLockLevel)
         if sfSideEffect in a.sym.flags: markSideEffect(tracked, a, n.info)
       else:
-        mergeLockLevels(tracked, n, op.lockLevel)
+        discard
       var effectList = op.n[0]
       if a.kind == nkSym and a.sym.kind == skMethod:
         propagateEffects(tracked, n, a.sym)
@@ -967,7 +912,6 @@ proc trackCall(tracked: PEffects; n: PNode) =
 type
   PragmaBlockContext = object
     oldLocked: int
-    oldLockLevel: TLockLevel
     enforcedGcSafety, enforceNoSideEffects: bool
     oldExc, oldTags, oldForbids: int
     exc, tags, forbids: PNode
@@ -976,7 +920,6 @@ proc createBlockContext(tracked: PEffects): PragmaBlockContext =
   var oldForbidsLen = 0
   if tracked.forbids != nil: oldForbidsLen = tracked.forbids.len
   result = PragmaBlockContext(oldLocked: tracked.locked.len,
-    oldLockLevel: tracked.currLockLevel,
     enforcedGcSafety: false, enforceNoSideEffects: false,
     oldExc: tracked.exc.len, oldTags: tracked.tags.len,
     oldForbids: oldForbidsLen)
@@ -989,7 +932,6 @@ 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'.
@@ -1396,17 +1338,6 @@ proc checkMethodEffects*(g: ModuleGraph; disp, branch: PSym) =
       localError(g.config, branch.info, "for method '" & branch.name.s &
         "' the `.requires` or `.ensures` properties are incompatible.")
 
-  if branch.typ.lockLevel > disp.typ.lockLevel:
-    when true:
-      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(g.config, branch.info,
-        "base method has lock level $1, but dispatcher has $2" %
-          [$branch.typ.lockLevel, $disp.typ.lockLevel])
-
 proc setEffectsForProcType*(g: ModuleGraph; t: PType, n: PNode; s: PSym = nil) =
   var effects = t.n[0]
   if t.kind != tyProc or effects.kind != nkEffectList: return
@@ -1592,13 +1523,6 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
     s.typ.flags.incl tfGcSafe
   if not t.hasSideEffect and sfSideEffect notin s.flags:
     s.typ.flags.incl tfNoSideEffect
-  if s.typ.lockLevel == UnspecifiedLockLevel:
-    s.typ.lockLevel = t.maxLockLevel
-  elif t.maxLockLevel > s.typ.lockLevel:
-    #localError(s.info,
-    message(g.config, s.info, warnLockLevel,
-      "declared lock level is $1, but real lock level is $2" %
-        [$s.typ.lockLevel, $t.maxLockLevel])
   when defined(drnim):
     if c.graph.strongSemCheck != nil: c.graph.strongSemCheck(c.graph, s, body)
   when defined(useDfa):
diff --git a/compiler/types.nim b/compiler/types.nim
index 1737fd48b..44cbf7ae1 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -48,7 +48,6 @@ type
   ProcConvMismatch* = enum
     pcmNoSideEffect
     pcmNotGcSafe
-    pcmLockDifference
     pcmNotIterator
     pcmDifferentCallConv
 
@@ -728,9 +727,6 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
       if tfThread in t.flags:
         addSep(prag)
         prag.add("gcsafe")
-      if t.lockLevel.ord != UnspecifiedLockLevel.ord:
-        addSep(prag)
-        prag.add("locks: " & $t.lockLevel)
       if prag.len != 0: result.add("{." & prag & ".}")
     of tyVarargs:
       result = typeToStr[t.kind] % typeToString(t[0])
@@ -1386,7 +1382,6 @@ type
     efRaisesUnknown
     efTagsDiffer
     efTagsUnknown
-    efLockLevelsDiffer
     efEffectsDelayed
     efTagsIllegal
 
@@ -1430,17 +1425,13 @@ proc compatibleEffects*(formal, actual: PType): EffectsCompat =
       elif hasIncompatibleEffect(sn, real[tagEffects]):
         return efTagsIllegal
 
-  if formal.lockLevel.ord < 0 or
-      actual.lockLevel.ord <= formal.lockLevel.ord:
+  for i in 1 ..< min(formal.n.len, actual.n.len):
+    if formal.n[i].sym.flags * {sfEffectsDelayed} != actual.n[i].sym.flags * {sfEffectsDelayed}:
+      result = efEffectsDelayed
+      break
 
-    for i in 1 ..< min(formal.n.len, actual.n.len):
-      if formal.n[i].sym.flags * {sfEffectsDelayed} != actual.n[i].sym.flags * {sfEffectsDelayed}:
-        result = efEffectsDelayed
-        break
+  result = efCompat
 
-    result = efCompat
-  else:
-    result = efLockLevelsDiffer
 
 proc isCompileTimeOnly*(t: PType): bool {.inline.} =
   result = t.kind in {tyTypeDesc, tyStatic}
@@ -1577,13 +1568,6 @@ proc getProcConvMismatch*(c: ConfigRef, f, a: PType, rel = isNone): (set[ProcCon
       result[1] = isNone
       result[0].incl pcmDifferentCallConv
 
-  if f.lockLevel.ord != UnspecifiedLockLevel.ord and
-     a.lockLevel.ord != UnspecifiedLockLevel.ord:
-       # proctypeRel has more logic to catch this difference,
-       # so dont need to do `rel = isNone`
-       # but it's a pragma mismatch reason which is why it's here
-       result[0].incl pcmLockDifference
-
 proc addPragmaAndCallConvMismatch*(message: var string, formal, actual: PType, conf: ConfigRef) =
   assert formal.kind == tyProc and actual.kind == tyProc
   let (convMismatch, _) = getProcConvMismatch(conf, formal, actual)
@@ -1598,9 +1582,6 @@ proc addPragmaAndCallConvMismatch*(message: var string, formal, actual: PType, c
       expectedPragmas.add "noSideEffect, "
     of pcmNotGcSafe:
       expectedPragmas.add "gcsafe, "
-    of pcmLockDifference:
-      gotPragmas.add("locks: " & $actual.lockLevel & ", ")
-      expectedPragmas.add("locks: " & $formal.lockLevel & ", ")
     of pcmNotIterator: discard
 
   if expectedPragmas.len > 0:
@@ -1621,8 +1602,6 @@ proc processPragmaAndCallConvMismatch(msg: var string, formal, actual: PType, co
       msg.add "\n.tag effects differ"
     of efTagsUnknown:
       msg.add "\n.tag effect is 'any tag allowed'"
-    of efLockLevelsDiffer:
-      msg.add "\nlock levels differ"
     of efEffectsDelayed:
       msg.add "\n.effectsOf annotations differ"
     of efTagsIllegal:
diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md
index cef4ff265..59d6a407b 100644
--- a/doc/manual_experimental.md
+++ b/doc/manual_experimental.md
@@ -1817,105 +1817,6 @@ restrictions / changes:
   yet performed for ordinary slices outside of a `parallel` section.
 
 
-
-Lock levels
-===========
-
-Lock levels are used to enforce a global locking order in order to detect
-potential deadlocks during semantic analysis. A lock level is an constant
-integer in the range 0..1_000. Lock level 0 means that no lock is acquired at
-all.
-
-If a section of code holds a lock of level `M`, it can also acquire any
-lock of level `N < M`. Another lock of level `M` cannot be acquired. Locks
-of the same level can only be acquired *at the same time* within a
-single `locks` section:
-
-  ```nim
-  var a, b: TLock[2]
-  var x: TLock[1]
-  # invalid locking order: TLock[1] cannot be acquired before TLock[2]:
-  {.locks: [x].}:
-    {.locks: [a].}:
-      ...
-  # valid locking order: TLock[2] acquired before TLock[1]:
-  {.locks: [a].}:
-    {.locks: [x].}:
-      ...
-
-  # invalid locking order: TLock[2] acquired before TLock[2]:
-  {.locks: [a].}:
-    {.locks: [b].}:
-      ...
-
-  # valid locking order, locks of the same level acquired at the same time:
-  {.locks: [a, b].}:
-    ...
-  ```
-
-
-Here is how a typical multilock statement can be implemented in Nim. Note how
-the runtime check is required to ensure a global ordering for two locks `a`
-and `b` of the same lock level:
-
-  ```nim
-  template multilock(a, b: ptr TLock; body: untyped) =
-    if cast[ByteAddress](a) < cast[ByteAddress](b):
-      pthread_mutex_lock(a)
-      pthread_mutex_lock(b)
-    else:
-      pthread_mutex_lock(b)
-      pthread_mutex_lock(a)
-    {.locks: [a, b].}:
-      try:
-        body
-      finally:
-        pthread_mutex_unlock(a)
-        pthread_mutex_unlock(b)
-  ```
-
-
-Whole routines can also be annotated with a `locks` pragma that takes a lock
-level. This then means that the routine may acquire locks of up to this level.
-This is essential so that procs can be called within a `locks` section:
-
-  ```nim
-  proc p() {.locks: 3.} = discard
-
-  var a: TLock[4]
-  {.locks: [a].}:
-    # p's locklevel (3) is strictly less than a's (4) so the call is allowed:
-    p()
-  ```
-
-
-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:
-
-  ```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()
-  ```
-
-This feature may be removed in the future due to its practical difficulties.
-
-
 Strict definitions and `out` parameters
 =======================================
 
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 595d4bab5..d09ea2fe2 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -215,12 +215,12 @@ template `or`*(x, y: NimNode): NimNode =
     y
 
 proc add*(father, child: NimNode): NimNode {.magic: "NAdd", discardable,
-  noSideEffect, locks: 0.}
+  noSideEffect.}
   ## Adds the `child` to the `father` node. Returns the
   ## father node so that calls can be nested.
 
 proc add*(father: NimNode, children: varargs[NimNode]): NimNode {.
-  magic: "NAddMultiple", discardable, noSideEffect, locks: 0.}
+  magic: "NAddMultiple", discardable, noSideEffect.}
   ## Adds each child of `children` to the `father` node.
   ## Returns the `father` node so that calls can be nested.
 
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index 16390d9af..8dd9e2c8b 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -1025,7 +1025,7 @@ proc bindAddr*(socket: Socket, port = Port(0), address = "") {.
 proc acceptAddr*(server: Socket, client: var owned(Socket), address: var string,
                  flags = {SocketFlag.SafeDisconn},
                  inheritable = defined(nimInheritHandles)) {.
-                 tags: [ReadIOEffect], gcsafe, locks: 0.} =
+                 tags: [ReadIOEffect], gcsafe.} =
   ## Blocks until a connection is being made from a client. When a connection
   ## is made sets `client` to the client socket and `address` to the address
   ## of the connecting client.
diff --git a/lib/pure/nimprof.nim b/lib/pure/nimprof.nim
index 3b1f703e3..6ee9de0a4 100644
--- a/lib/pure/nimprof.nim
+++ b/lib/pure/nimprof.nim
@@ -122,13 +122,13 @@ when defined(memProfiler):
   var
     gTicker {.threadvar.}: int
 
-  proc requestedHook(): bool {.nimcall, locks: 0.} =
+  proc requestedHook(): bool {.nimcall.} =
     if gTicker == 0:
       gTicker = SamplingInterval
       result = true
     dec gTicker
 
-  proc hook(st: StackTrace, size: int) {.nimcall, locks: 0.} =
+  proc hook(st: StackTrace, size: int) {.nimcall.} =
     when defined(ignoreAllocationSize):
       hookAux(st, 1)
     else:
@@ -140,7 +140,7 @@ else:
     gTicker: int # we use an additional counter to
                  # avoid calling 'getTicks' too frequently
 
-  proc requestedHook(): bool {.nimcall, locks: 0.} =
+  proc requestedHook(): bool {.nimcall.} =
     if interval == 0: result = true
     elif gTicker == 0:
       gTicker = 500
@@ -149,7 +149,7 @@ else:
     else:
       dec gTicker
 
-  proc hook(st: StackTrace) {.nimcall, locks: 0.} =
+  proc hook(st: StackTrace) {.nimcall.} =
     #echo "profiling! ", interval
     if interval == 0:
       hookAux(st, 1)
diff --git a/lib/pure/nimtracker.nim b/lib/pure/nimtracker.nim
index a66dfc2ea..91bb07192 100644
--- a/lib/pure/nimtracker.nim
+++ b/lib/pure/nimtracker.nim
@@ -34,7 +34,7 @@ template sbind(x: int; value) =
       quit "could not bind value"
 
 when defined(memTracker):
-  proc logEntries(log: TrackLog) {.nimcall, locks: 0, tags: [], gcsafe.} =
+  proc logEntries(log: TrackLog) {.nimcall, tags: [], gcsafe.} =
     if insertStmt.isNil:
       if prepare_v2(dbHandle, insertQuery,
           insertQuery.len, insertStmt, nil) != SQLITE_OK:
diff --git a/lib/system/cyclebreaker.nim b/lib/system/cyclebreaker.nim
index 6ec0f01f7..4427ae53b 100644
--- a/lib/system/cyclebreaker.nim
+++ b/lib/system/cyclebreaker.nim
@@ -148,7 +148,7 @@ proc thinout*[T](x: ref T) {.inline.} =
   ## and thus would keep the graph from being freed are `nil`'ed.
   ## This is a form of cycle collection that works well with Nim's ARC
   ## and its associated cost model.
-  proc getDynamicTypeInfo[T](x: T): PNimTypeV2 {.magic: "GetTypeInfoV2", noSideEffect, locks: 0.}
+  proc getDynamicTypeInfo[T](x: T): PNimTypeV2 {.magic: "GetTypeInfoV2", noSideEffect.}
 
   breakCycles(head(cast[pointer](x)), getDynamicTypeInfo(x[]))
 
diff --git a/lib/system/inclrtl.nim b/lib/system/inclrtl.nim
index ca41f39c6..42c85ad26 100644
--- a/lib/system/inclrtl.nim
+++ b/lib/system/inclrtl.nim
@@ -45,7 +45,7 @@ else:
   {.pragma: inl, inline.}
   {.pragma: compilerRtl, compilerproc.}
 
-{.pragma: benign, gcsafe, locks: 0.}
+{.pragma: benign, gcsafe.}
 
 when defined(nimHasSinkInference):
   {.push sinkInference: on.}
diff --git a/lib/system/memalloc.nim b/lib/system/memalloc.nim
index f8ebc8c5f..7660bcd58 100644
--- a/lib/system/memalloc.nim
+++ b/lib/system/memalloc.nim
@@ -1,13 +1,13 @@
 when notJSnotNims:
   proc zeroMem*(p: pointer, size: Natural) {.inline, noSideEffect,
-    tags: [], locks: 0, raises: [].}
+    tags: [], raises: [].}
     ## Overwrites the contents of the memory at `p` with the value 0.
     ##
     ## Exactly `size` bytes will be overwritten. Like any procedure
     ## dealing with raw memory this is **unsafe**.
 
   proc copyMem*(dest, source: pointer, size: Natural) {.inline, benign,
-    tags: [], locks: 0, raises: [].}
+    tags: [], raises: [].}
     ## Copies the contents from the memory at `source` to the memory
     ## at `dest`.
     ## Exactly `size` bytes will be copied. The memory
@@ -15,7 +15,7 @@ when notJSnotNims:
     ## memory this is **unsafe**.
 
   proc moveMem*(dest, source: pointer, size: Natural) {.inline, benign,
-    tags: [], locks: 0, raises: [].}
+    tags: [], raises: [].}
     ## Copies the contents from the memory at `source` to the memory
     ## at `dest`.
     ##
@@ -25,7 +25,7 @@ when notJSnotNims:
     ## dealing with raw memory this is still **unsafe**, though.
 
   proc equalMem*(a, b: pointer, size: Natural): bool {.inline, noSideEffect,
-    tags: [], locks: 0, raises: [].}
+    tags: [], raises: [].}
     ## Compares the memory blocks `a` and `b`. `size` bytes will
     ## be compared.
     ##
@@ -34,7 +34,7 @@ when notJSnotNims:
     ## **unsafe**.
 
   proc cmpMem*(a, b: pointer, size: Natural): int {.inline, noSideEffect,
-    tags: [], locks: 0, raises: [].}
+    tags: [], raises: [].}
     ## Compares the memory blocks `a` and `b`. `size` bytes will
     ## be compared.
     ##
diff --git a/lib/system/memtracker.nim b/lib/system/memtracker.nim
index f0c83f1fa..9d2d7caee 100644
--- a/lib/system/memtracker.nim
+++ b/lib/system/memtracker.nim
@@ -35,7 +35,7 @@ type
     count*: int
     disabled: bool
     data*: array[400, LogEntry]
-  TrackLogger* = proc (log: TrackLog) {.nimcall, tags: [], locks: 0, gcsafe.}
+  TrackLogger* = proc (log: TrackLog) {.nimcall, tags: [], gcsafe.}
 
 var
   gLog*: TrackLog
@@ -70,7 +70,7 @@ proc addEntry(entry: LogEntry) =
     if interesting:
       gLog.disabled = true
       cprintf("interesting %s:%ld %s\n", entry.file, entry.line, entry.op)
-      let x = cast[proc() {.nimcall, tags: [], gcsafe, locks: 0, raises: [].}](writeStackTrace)
+      let x = cast[proc() {.nimcall, tags: [], gcsafe, raises: [].}](writeStackTrace)
       x()
       quit 1
       #if gLog.count > high(gLog.data):
@@ -85,7 +85,7 @@ proc memTrackerWrite(address: pointer; size: int; file: cstring; line: int) {.co
       size: size, file: file, line: line, thread: myThreadId())
 
 proc memTrackerOp*(op: cstring; address: pointer; size: int) {.tags: [],
-         locks: 0, gcsafe.} =
+         gcsafe.} =
   addEntry LogEntry(op: op, address: address, size: size,
       file: "", line: 0, thread: myThreadId())
 
diff --git a/lib/system/profiler.nim b/lib/system/profiler.nim
index 0649f1176..e7eb6ac82 100644
--- a/lib/system/profiler.nim
+++ b/lib/system/profiler.nim
@@ -60,13 +60,13 @@ proc captureStackTrace(f: PFrame, st: var StackTrace) =
     b = b.prev
 
 var
-  profilingRequestedHook*: proc (): bool {.nimcall, locks: 0, gcsafe.}
+  profilingRequestedHook*: proc (): bool {.nimcall, gcsafe.}
     ## set this variable to provide a procedure that implements a profiler in
     ## user space. See the `nimprof` module for a reference implementation.
 
 when defined(memProfiler):
   type
-    MemProfilerHook* = proc (st: StackTrace, requestedSize: int) {.nimcall, locks: 0, gcsafe.}
+    MemProfilerHook* = proc (st: StackTrace, requestedSize: int) {.nimcall, gcsafe.}
 
   var
     profilerHook*: MemProfilerHook
diff --git a/lib/system/stacktraces.nim b/lib/system/stacktraces.nim
index 8142f8c7b..42be9d94f 100644
--- a/lib/system/stacktraces.nim
+++ b/lib/system/stacktraces.nim
@@ -22,26 +22,26 @@ when defined(nimStackTraceOverride):
       ## This is the same as the type `uintptr_t` in C.
 
     StackTraceOverrideGetTracebackProc* = proc (): string {.
-      nimcall, gcsafe, locks: 0, raises: [], tags: [], noinline.}
+      nimcall, gcsafe, raises: [], tags: [], noinline.}
     StackTraceOverrideGetProgramCountersProc* = proc (maxLength: cint): seq[cuintptr_t] {.
-      nimcall, gcsafe, locks: 0, raises: [], tags: [], noinline.}
+      nimcall, gcsafe, raises: [], tags: [], noinline.}
     StackTraceOverrideGetDebuggingInfoProc* =
       proc (programCounters: seq[cuintptr_t], maxLength: cint): seq[StackTraceEntry] {.
-        nimcall, gcsafe, locks: 0, raises: [], tags: [], noinline.}
+        nimcall, gcsafe, raises: [], tags: [], noinline.}
 
   # Default procedures (not normally used, because people opting in on this
   # override are supposed to register their own versions).
   var
     stackTraceOverrideGetTraceback: StackTraceOverrideGetTracebackProc =
-      proc (): string {.nimcall, gcsafe, locks: 0, raises: [], tags: [], noinline.} =
+      proc (): string {.nimcall, gcsafe, raises: [], tags: [], noinline.} =
         discard
         #result = "Stack trace override procedure not registered.\n"
     stackTraceOverrideGetProgramCounters: StackTraceOverrideGetProgramCountersProc =
-      proc (maxLength: cint): seq[cuintptr_t] {.nimcall, gcsafe, locks: 0, raises: [], tags: [], noinline.} =
+      proc (maxLength: cint): seq[cuintptr_t] {.nimcall, gcsafe, raises: [], tags: [], noinline.} =
         discard
     stackTraceOverrideGetDebuggingInfo: StackTraceOverrideGetDebuggingInfoProc =
       proc (programCounters: seq[cuintptr_t], maxLength: cint): seq[StackTraceEntry] {.
-        nimcall, gcsafe, locks: 0, raises: [], tags: [], noinline.} =
+        nimcall, gcsafe, raises: [], tags: [], noinline.} =
           discard
 
   # Custom procedure registration.
diff --git a/lib/wrappers/sqlite3.nim b/lib/wrappers/sqlite3.nim
index 71921c10b..96c37e09c 100644
--- a/lib/wrappers/sqlite3.nim
+++ b/lib/wrappers/sqlite3.nim
@@ -121,7 +121,7 @@ type
 
   Callback* = proc (para1: pointer, para2: int32, para3,
                      para4: cstringArray): int32{.cdecl.}
-  Tbind_destructor_func* = proc (para1: pointer){.cdecl, locks: 0, tags: [], gcsafe.}
+  Tbind_destructor_func* = proc (para1: pointer){.cdecl, tags: [], gcsafe.}
   Create_function_step_func* = proc (para1: Pcontext, para2: int32,
                                       para3: PValueArg){.cdecl.}
   Create_function_func_func* = proc (para1: Pcontext, para2: int32,
diff --git a/nimsuggest/tests/tdef1.nim b/nimsuggest/tests/tdef1.nim
index 2cd040ea1..5c86923b6 100644
--- a/nimsuggest/tests/tdef1.nim
+++ b/nimsuggest/tests/tdef1.nim
@@ -1,9 +1,9 @@
 discard """
 $nimsuggest --tester $file
 >def $1
-def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe, locks: 0.};;$file;;9;;5;;"Return hello";;100
+def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe.};;$file;;9;;5;;"Return hello";;100
 >def $1
-def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe, locks: 0.};;$file;;9;;5;;"Return hello";;100
+def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe.};;$file;;9;;5;;"Return hello";;100
 """
 
 proc hello(): string =
diff --git a/nimsuggest/tests/tdot4.nim b/nimsuggest/tests/tdot4.nim
index e1ff96553..8681d045a 100644
--- a/nimsuggest/tests/tdot4.nim
+++ b/nimsuggest/tests/tdot4.nim
@@ -15,7 +15,7 @@ discard """
 $nimsuggest --tester --maxresults:2 $file
 >sug $1
 sug;;skProc;;tdot4.main;;proc (inp: string): string;;$file;;6;;5;;"";;100;;None
-sug;;skFunc;;mstrutils.replace;;proc (s: string, sub: string, by: string): string{.noSideEffect, gcsafe, locks: 0.};;*fixtures/mstrutils.nim;;9;;5;;"this is a test version of strutils.replace, it simply returns `by`";;100;;None
+sug;;skFunc;;mstrutils.replace;;proc (s: string, sub: string, by: string): string{.noSideEffect, gcsafe.};;*fixtures/mstrutils.nim;;9;;5;;"this is a test version of strutils.replace, it simply returns `by`";;100;;None
 """
 
 # TODO - determine appropriate behaviour for further suggest output and test it
diff --git a/nimsuggest/tests/tinclude.nim b/nimsuggest/tests/tinclude.nim
index b67440b9e..66726f907 100644
--- a/nimsuggest/tests/tinclude.nim
+++ b/nimsuggest/tests/tinclude.nim
@@ -11,7 +11,7 @@ go()
 discard """
 $nimsuggest --tester $file
 >def $path/tinclude.nim:7:14
-def;;skProc;;minclude_import.create;;proc (greeting: string, subject: string): Greet{.noSideEffect, gcsafe, locks: 0.};;*fixtures/minclude_include.nim;;3;;5;;"";;100
+def;;skProc;;minclude_import.create;;proc (greeting: string, subject: string): Greet{.noSideEffect, gcsafe.};;*fixtures/minclude_include.nim;;3;;5;;"";;100
 >def $path/fixtures/minclude_include.nim:3:71
 def;;skType;;minclude_types.Greet;;Greet;;*fixtures/minclude_types.nim;;4;;2;;"";;100
 >def $path/fixtures/minclude_include.nim:3:71
diff --git a/nimsuggest/tests/tsug_template.nim b/nimsuggest/tests/tsug_template.nim
index 15615f0af..a2558c81c 100644
--- a/nimsuggest/tests/tsug_template.nim
+++ b/nimsuggest/tests/tsug_template.nim
@@ -6,7 +6,7 @@ tmp#[!]#
 discard """
 $nimsuggest --tester $file
 >sug $1
-sug;;skMacro;;tsug_template.tmpb;;macro (){.noSideEffect, gcsafe, locks: 0.};;$file;;2;;6;;"";;100;;Prefix
+sug;;skMacro;;tsug_template.tmpb;;macro (){.noSideEffect, gcsafe.};;$file;;2;;6;;"";;100;;Prefix
 sug;;skConverter;;tsug_template.tmpc;;converter ();;$file;;3;;10;;"";;100;;Prefix
 sug;;skTemplate;;tsug_template.tmpa;;template ();;$file;;1;;9;;"";;100;;Prefix
 """
diff --git a/nimsuggest/tests/tuse.nim b/nimsuggest/tests/tuse.nim
index 89a9c151a..deaf81ef2 100644
--- a/nimsuggest/tests/tuse.nim
+++ b/nimsuggest/tests/tuse.nim
@@ -14,9 +14,9 @@ proc #[!]#someProc*() =
 discard """
 $nimsuggest --tester $file
 >use $1
-def;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe, locks: 0.};;$file;;9;;5;;"";;100
-use;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe, locks: 0.};;$file;;12;;0;;"";;100
+def;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe.};;$file;;9;;5;;"";;100
+use;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe.};;$file;;12;;0;;"";;100
 >use $2
-def;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe, locks: 0.};;$file;;9;;5;;"";;100
-use;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe, locks: 0.};;$file;;12;;0;;"";;100
+def;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe.};;$file;;9;;5;;"";;100
+use;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe.};;$file;;12;;0;;"";;100
 """
diff --git a/nimsuggest/tests/tv3.nim b/nimsuggest/tests/tv3.nim
index 57ad86e4d..9d8b1ef2d 100644
--- a/nimsuggest/tests/tv3.nim
+++ b/nimsuggest/tests/tv3.nim
@@ -19,11 +19,11 @@ def	skField	tv3.Foo.bar	string	$file	5	4	""	100
 >outline $1
 outline	skType	tv3.Foo	Foo	$file	4	2	""	100
 outline	skField	tv3.Foo.bar	string	$file	5	4	""	100
-outline	skProc	tv3.test	proc (f: Foo){.gcsafe, locks: 0.}	$file	7	5	""	100
+outline	skProc	tv3.test	proc (f: Foo){.gcsafe.}	$file	7	5	""	100
 >sug $1
 sug	skField	bar	string	$file	5	4	""	100	Prefix
 >globalSymbols test
-def	skProc	tv3.test	proc (f: Foo){.gcsafe, locks: 0.}	$file	7	5	""	100
+def	skProc	tv3.test	proc (f: Foo){.gcsafe.}	$file	7	5	""	100
 >globalSymbols Foo
 def	skType	tv3.Foo	Foo	$file	4	2	""	100
 >def $2
diff --git a/nimsuggest/tests/tv3_forward_definition.nim b/nimsuggest/tests/tv3_forward_definition.nim
index 14c0dc2e2..392e019ff 100644
--- a/nimsuggest/tests/tv3_forward_definition.nim
+++ b/nimsuggest/tests/tv3_forward_definition.nim
@@ -7,17 +7,17 @@ let a = de#[!]#mo()
 discard """
 $nimsuggest --v3 --tester $file
 >use $1
-use	skProc	tv3_forward_definition.demo	proc (): int{.noSideEffect, gcsafe, locks: 0.}	$file	1	5	""	100
-def	skProc	tv3_forward_definition.demo	proc (): int{.noSideEffect, gcsafe, locks: 0.}	$file	3	5	""	100
-use	skProc	tv3_forward_definition.demo	proc (): int{.noSideEffect, gcsafe, locks: 0.}	$file	5	8	""	100
+use	skProc	tv3_forward_definition.demo	proc (): int{.noSideEffect, gcsafe.}	$file	1	5	""	100
+def	skProc	tv3_forward_definition.demo	proc (): int{.noSideEffect, gcsafe.}	$file	3	5	""	100
+use	skProc	tv3_forward_definition.demo	proc (): int{.noSideEffect, gcsafe.}	$file	5	8	""	100
 >use $2
-use	skProc	tv3_forward_definition.demo	proc (): int{.noSideEffect, gcsafe, locks: 0.}	$file	1	5	""	100
-def	skProc	tv3_forward_definition.demo	proc (): int{.noSideEffect, gcsafe, locks: 0.}	$file	3	5	""	100
-use	skProc	tv3_forward_definition.demo	proc (): int{.noSideEffect, gcsafe, locks: 0.}	$file	5	8	""	100
+use	skProc	tv3_forward_definition.demo	proc (): int{.noSideEffect, gcsafe.}	$file	1	5	""	100
+def	skProc	tv3_forward_definition.demo	proc (): int{.noSideEffect, gcsafe.}	$file	3	5	""	100
+use	skProc	tv3_forward_definition.demo	proc (): int{.noSideEffect, gcsafe.}	$file	5	8	""	100
 >declaration $1
-declaration	skProc	tv3_forward_definition.demo	proc (): int{.noSideEffect, gcsafe, locks: 0.}	$file	3	5	""	100
+declaration	skProc	tv3_forward_definition.demo	proc (): int{.noSideEffect, gcsafe.}	$file	3	5	""	100
 >declaration $2
-declaration	skProc	tv3_forward_definition.demo	proc (): int{.noSideEffect, gcsafe, locks: 0.}	$file	1	5	""	100
+declaration	skProc	tv3_forward_definition.demo	proc (): int{.noSideEffect, gcsafe.}	$file	1	5	""	100
 >declaration $3
-declaration	skProc	tv3_forward_definition.demo	proc (): int{.noSideEffect, gcsafe, locks: 0.}	$file	1	5	""	100
+declaration	skProc	tv3_forward_definition.demo	proc (): int{.noSideEffect, gcsafe.}	$file	1	5	""	100
 """
diff --git a/nimsuggest/tests/tv3_globalSymbols.nim b/nimsuggest/tests/tv3_globalSymbols.nim
index 85814cadd..f965a07aa 100644
--- a/nimsuggest/tests/tv3_globalSymbols.nim
+++ b/nimsuggest/tests/tv3_globalSymbols.nim
@@ -7,8 +7,8 @@ proc BBtokenA(): int = 5
 discard """
 $nimsuggest --v3 --tester $file
 >globalSymbols token
-def	skProc	tv3_globalSymbols.token	proc (): int{.noSideEffect, gcsafe, locks: 0.}	$file	4	5	""	100
-def	skProc	tv3_globalSymbols.tokenA	proc (): int{.noSideEffect, gcsafe, locks: 0.}	$file	3	5	""	100
-def	skProc	tv3_globalSymbols.Btoken	proc (): int{.noSideEffect, gcsafe, locks: 0.}	$file	2	5	""	100
-def	skProc	tv3_globalSymbols.BBtokenA	proc (): int{.noSideEffect, gcsafe, locks: 0.}	$file	5	5	""	100
+def	skProc	tv3_globalSymbols.token	proc (): int{.noSideEffect, gcsafe.}	$file	4	5	""	100
+def	skProc	tv3_globalSymbols.tokenA	proc (): int{.noSideEffect, gcsafe.}	$file	3	5	""	100
+def	skProc	tv3_globalSymbols.Btoken	proc (): int{.noSideEffect, gcsafe.}	$file	2	5	""	100
+def	skProc	tv3_globalSymbols.BBtokenA	proc (): int{.noSideEffect, gcsafe.}	$file	5	5	""	100
 """
diff --git a/tests/arc/twrong_sinkinference.nim b/tests/arc/twrong_sinkinference.nim
index 59930a9fa..ecf09d28a 100644
--- a/tests/arc/twrong_sinkinference.nim
+++ b/tests/arc/twrong_sinkinference.nim
@@ -1,6 +1,6 @@
 discard """
   cmd: "nim c --gc:arc $file"
-  errormsg: "type mismatch: got <proc (a: string, b: sink string){.noSideEffect, gcsafe, locks: 0.}>"
+  errormsg: "type mismatch: got <proc (a: string, b: sink string){.noSideEffect, gcsafe.}>"
   line: 18
 """
 
diff --git a/tests/bind/tnicerrorforsymchoice.nim b/tests/bind/tnicerrorforsymchoice.nim
index 684b83239..6001b6b09 100644
--- a/tests/bind/tnicerrorforsymchoice.nim
+++ b/tests/bind/tnicerrorforsymchoice.nim
@@ -1,5 +1,5 @@
 discard """
-  errormsg: "type mismatch: got <proc (s: TScgi: ScgiState or AsyncScgiState) | proc (client: AsyncSocket, headers: StringTableRef, input: string){.noSideEffect, gcsafe, locks: 0.}>"
+  errormsg: "type mismatch: got <proc (s: TScgi: ScgiState or AsyncScgiState) | proc (client: AsyncSocket, headers: StringTableRef, input: string){.noSideEffect, gcsafe.}>"
   line: 23
 """
 
diff --git a/tests/closure/tclosure.nim b/tests/closure/tclosure.nim
index 8ae6c44bb..1bbe4cd0d 100644
--- a/tests/closure/tclosure.nim
+++ b/tests/closure/tclosure.nim
@@ -65,7 +65,7 @@ block tclosure:
 
   # bug #5015
 
-  type Mutator = proc(matched: string): string {.noSideEffect, gcsafe, locks: 0.}
+  type Mutator = proc(matched: string): string {.noSideEffect, gcsafe.}
 
   proc putMutated(
       MutatorCount: static[int],
diff --git a/tests/closure/tinvalidclosure.nim b/tests/closure/tinvalidclosure.nim
index 47f3f105f..37d0f68a2 100644
--- a/tests/closure/tinvalidclosure.nim
+++ b/tests/closure/tinvalidclosure.nim
@@ -1,5 +1,5 @@
 discard """
-  errormsg: "type mismatch: got <proc (x: int){.nimcall, gcsafe, locks: 0.}>"
+  errormsg: "type mismatch: got <proc (x: int){.nimcall, gcsafe.}>"
   line: 12
 """
 
diff --git a/tests/closure/tinvalidclosure5.nim b/tests/closure/tinvalidclosure5.nim
index d03d93867..3b5f46a40 100644
--- a/tests/closure/tinvalidclosure5.nim
+++ b/tests/closure/tinvalidclosure5.nim
@@ -1,5 +1,5 @@
 discard """
-  errormsg: "type mismatch: got <proc (){.closure, gcsafe, locks: 0.}> but expected 'A = proc (){.nimcall.}'"
+  errormsg: "type mismatch: got <proc (){.closure, gcsafe.}> but expected 'A = proc (){.nimcall.}'"
   line: 9
 """
 
diff --git a/tests/closure/tnested.nim b/tests/closure/tnested.nim
index ca8d0e08b..405ebd9b9 100644
--- a/tests/closure/tnested.nim
+++ b/tests/closure/tnested.nim
@@ -33,7 +33,7 @@ py
 py
 px
 6
-proc (){.closure, gcsafe, locks: 0.}
+proc (){.closure, gcsafe.}
 '''
 """
 
diff --git a/tests/effects/teffects1.nim b/tests/effects/teffects1.nim
index ca9021999..68bafa94d 100644
--- a/tests/effects/teffects1.nim
+++ b/tests/effects/teffects1.nim
@@ -34,7 +34,7 @@ proc foo(x: int): string {.nimcall, raises: [ValueError].} =
 
 var p: MyProcType = foo #[tt.Error
                     ^
-type mismatch: got <proc (x: int): string{.nimcall, noSideEffect, gcsafe, locks: 0.}> but expected 'MyProcType = proc (x: int): string{.closure.}'
+type mismatch: got <proc (x: int): string{.nimcall, noSideEffect, gcsafe.}> but expected 'MyProcType = proc (x: int): string{.closure.}'
   Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'.
 .raise effects differ
 ]#
diff --git a/tests/effects/teffects11.nim b/tests/effects/teffects11.nim
index e4098e959..20b7026ab 100644
--- a/tests/effects/teffects11.nim
+++ b/tests/effects/teffects11.nim
@@ -1,6 +1,6 @@
 discard """
 action: compile
-errormsg: "type mismatch: got <proc (x: int){.gcsafe, locks: 0.}>"
+errormsg: "type mismatch: got <proc (x: int){.gcsafe.}>"
 line: 21
 """
 
diff --git a/tests/effects/teffects19.nim b/tests/effects/teffects19.nim
index 49fb87523..6b4ab0819 100644
--- a/tests/effects/teffects19.nim
+++ b/tests/effects/teffects19.nim
@@ -1,6 +1,6 @@
 discard """
 action: compile
-errormsg: "type mismatch: got <proc (i: int){.gcsafe, locks: 0.}>"
+errormsg: "type mismatch: got <proc (i: int){.gcsafe.}>"
 line: 23
 """
 
diff --git a/tests/effects/tgcsafe2.nim b/tests/effects/tgcsafe2.nim
index 07da4e3f8..6268592a9 100644
--- a/tests/effects/tgcsafe2.nim
+++ b/tests/effects/tgcsafe2.nim
@@ -1,5 +1,5 @@
 discard """
-  errormsg: '''type mismatch: got <proc (s: string){.locks: 0.}>'''
+  errormsg: '''type mismatch: got <proc (s: string)>'''
   line: 11
 """
 #5620
diff --git a/tests/errmsgs/t10489_a.nim b/tests/errmsgs/t10489_a.nim
index 71a6cc3c4..c762ce876 100644
--- a/tests/errmsgs/t10489_a.nim
+++ b/tests/errmsgs/t10489_a.nim
@@ -1,5 +1,5 @@
 discard """
-errormsg: "invalid type: 'macro (body: untyped): untyped{.noSideEffect, gcsafe, locks: 0.}' for let. Did you mean to call the macro with '()'?"
+errormsg: "invalid type: 'macro (body: untyped): untyped{.noSideEffect, gcsafe.}' for let. Did you mean to call the macro with '()'?"
 line: 9
 """
 
diff --git a/tests/errmsgs/t10489_b.nim b/tests/errmsgs/t10489_b.nim
index 4b0b876e5..df05f0e6e 100644
--- a/tests/errmsgs/t10489_b.nim
+++ b/tests/errmsgs/t10489_b.nim
@@ -1,5 +1,5 @@
 discard """
-errormsg: "invalid type: 'macro (body: untyped): untyped{.noSideEffect, gcsafe, locks: 0.}' for const. Did you mean to call the macro with '()'?"
+errormsg: "invalid type: 'macro (body: untyped): untyped{.noSideEffect, gcsafe.}' for const. Did you mean to call the macro with '()'?"
 line: 9
 """
 
diff --git a/tests/errmsgs/t18886.nim b/tests/errmsgs/t18886.nim
index cad62d431..8ed160c64 100644
--- a/tests/errmsgs/t18886.nim
+++ b/tests/errmsgs/t18886.nim
@@ -3,8 +3,8 @@ discard """
   errormsg: ""
   nimout: '''
 t18886.nim(18, 24) Error: ambiguous identifier: 'bar' -- you need a helper proc to disambiguate the following:
-  t18886.bar: proc (i: ptr int){.noSideEffect, gcsafe, locks: 0.}
-  t18886.bar: proc (i: ptr char){.noSideEffect, gcsafe, locks: 0.}
+  t18886.bar: proc (i: ptr int){.noSideEffect, gcsafe.}
+  t18886.bar: proc (i: ptr char){.noSideEffect, gcsafe.}
 '''
 """
 
diff --git a/tests/errmsgs/t2614.nim b/tests/errmsgs/t2614.nim
index 4034249e7..031ecb9d1 100644
--- a/tests/errmsgs/t2614.nim
+++ b/tests/errmsgs/t2614.nim
@@ -2,9 +2,9 @@ discard """
   cmd: "nim check $options --hints:off $file"
   errormsg: ""
   nimout: '''
-t2614.nim(19, 27) Error: type mismatch: got <array[0..1, proc (){.locks: <unknown>.}]> but expected 'array[0..1, proc (){.closure.}]'
+t2614.nim(19, 27) Error: type mismatch: got <array[0..1, proc ()]> but expected 'array[0..1, proc (){.closure.}]'
   Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'.
-t2614.nim(21, 22) Error: type mismatch: got <seq[proc (){.locks: <unknown>.}]> but expected 'seq[proc (){.closure.}]'
+t2614.nim(21, 22) Error: type mismatch: got <seq[proc ()]> but expected 'seq[proc (){.closure.}]'
   Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'.
 '''
 """
diff --git a/tests/errmsgs/t5167_4.nim b/tests/errmsgs/t5167_4.nim
index 7a263622b..dafd7754d 100644
--- a/tests/errmsgs/t5167_4.nim
+++ b/tests/errmsgs/t5167_4.nim
@@ -1,5 +1,5 @@
 discard """
-errormsg: "type mismatch: got <proc [*missing parameters*](x: int) | proc (x: string){.gcsafe, locks: 0.}>"
+errormsg: "type mismatch: got <proc [*missing parameters*](x: int) | proc (x: string){.gcsafe.}>"
 line: 19
 """
 
diff --git a/tests/errmsgs/tgcsafety.nim b/tests/errmsgs/tgcsafety.nim
index 701adeebf..66496d364 100644
--- a/tests/errmsgs/tgcsafety.nim
+++ b/tests/errmsgs/tgcsafety.nim
@@ -1,8 +1,8 @@
 discard """
 cmd: "nim check $file"
-errormsg: "type mismatch: got <AsyncHttpServer, Port, proc (req: Request): Future[system.void]{.locks: <unknown>.}>"
+errormsg: "type mismatch: got <AsyncHttpServer, Port, proc (req: Request): Future[system.void]>"
 nimout: '''
-tgcsafety.nim(31, 18) Error: type mismatch: got <AsyncHttpServer, Port, proc (req: Request): Future[system.void]{.locks: <unknown>.}>
+tgcsafety.nim(31, 18) Error: type mismatch: got <AsyncHttpServer, Port, proc (req: Request): Future[system.void]>
 but expected one of:
 proc serve(server: AsyncHttpServer; port: Port;
            callback: proc (request: Request): Future[void] {.closure, gcsafe.};
@@ -10,7 +10,7 @@ proc serve(server: AsyncHttpServer; port: Port;
     Future[void])
   first type mismatch at position: 3
   required type for callback: proc (request: Request): Future[system.void]{.closure, gcsafe.}
-  but expression 'cb' is of type: proc (req: Request): Future[system.void]{.locks: <unknown>.}
+  but expression 'cb' is of type: proc (req: Request): Future[system.void]
   This expression is not GC-safe. Annotate the proc with {.gcsafe.} to get extended error information.
 
 expression: serve(server, Port(7898), cb)
diff --git a/tests/errmsgs/tproc_mismatch.nim b/tests/errmsgs/tproc_mismatch.nim
index f92589d96..16f319f3b 100644
--- a/tests/errmsgs/tproc_mismatch.nim
+++ b/tests/errmsgs/tproc_mismatch.nim
@@ -3,36 +3,36 @@ discard """
   cmd: '''nim check --hints:off $options $file'''
   nimoutFull: true
   nimout: '''
-tproc_mismatch.nim(38, 52) Error: type mismatch: got <proc (a: int, c: float){.cdecl, noSideEffect, gcsafe, locks: 0.}> but expected 'proc (a: int, c: float){.closure, noSideEffect.}'
+tproc_mismatch.nim(38, 52) Error: type mismatch: got <proc (a: int, c: float){.cdecl, noSideEffect, gcsafe.}> but expected 'proc (a: int, c: float){.closure, noSideEffect.}'
   Calling convention mismatch: got '{.cdecl.}', but expected '{.closure.}'.
-tproc_mismatch.nim(42, 6) Error: type mismatch: got <proc (){.inline, noSideEffect, gcsafe, locks: 0.}>
+tproc_mismatch.nim(42, 6) Error: type mismatch: got <proc (){.inline, noSideEffect, gcsafe.}>
 but expected one of:
 proc bar(a: proc ())
   first type mismatch at position: 1
   required type for a: proc (){.closure.}
-  but expression 'fn1' is of type: proc (){.inline, noSideEffect, gcsafe, locks: 0.}
+  but expression 'fn1' is of type: proc (){.inline, noSideEffect, gcsafe.}
   Calling convention mismatch: got '{.inline.}', but expected '{.closure.}'.
 
 expression: bar(fn1)
-tproc_mismatch.nim(46, 8) Error: type mismatch: got <proc (){.inline, noSideEffect, gcsafe, locks: 0.}> but expected 'proc (){.closure.}'
+tproc_mismatch.nim(46, 8) Error: type mismatch: got <proc (){.inline, noSideEffect, gcsafe.}> but expected 'proc (){.closure.}'
   Calling convention mismatch: got '{.inline.}', but expected '{.closure.}'.
-tproc_mismatch.nim(51, 8) Error: type mismatch: got <proc (){.locks: 0.}> but expected 'proc (){.closure, noSideEffect.}'
+tproc_mismatch.nim(51, 8) Error: type mismatch: got <proc ()> but expected 'proc (){.closure, noSideEffect.}'
   Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'.
   Pragma mismatch: got '{..}', but expected '{.noSideEffect.}'.
-tproc_mismatch.nim(55, 8) Error: type mismatch: got <proc (a: int){.noSideEffect, gcsafe, locks: 0.}> but expected 'proc (a: float){.closure.}'
+tproc_mismatch.nim(55, 8) Error: type mismatch: got <proc (a: int){.noSideEffect, gcsafe.}> but expected 'proc (a: float){.closure.}'
   Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'.
-tproc_mismatch.nim(64, 9) Error: type mismatch: got <proc (a: int){.locks: 0.}> but expected 'proc (a: int){.closure, gcsafe.}'
+tproc_mismatch.nim(64, 9) Error: type mismatch: got <proc (a: int)> but expected 'proc (a: int){.closure, gcsafe.}'
   Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'.
   Pragma mismatch: got '{..}', but expected '{.gcsafe.}'.
 tproc_mismatch.nim(72, 9) Error: type mismatch: got <proc (a: int): int{.nimcall.}> but expected 'proc (a: int): int{.cdecl.}'
   Calling convention mismatch: got '{.nimcall.}', but expected '{.cdecl.}'.
 tproc_mismatch.nim(73, 9) Error: type mismatch: got <proc (a: int): int{.cdecl.}> but expected 'proc (a: int): int{.nimcall.}'
   Calling convention mismatch: got '{.cdecl.}', but expected '{.nimcall.}'.
-tproc_mismatch.nim(77, 9) Error: type mismatch: got <proc (a: int){.closure, locks: 3.}> but expected 'proc (a: int){.closure, locks: 1.}'
-  Pragma mismatch: got '{.locks: 3.}', but expected '{.locks: 1.}'.
-lock levels differ
 '''
 """
+
+
+
 block: # CallConv mismatch
   func a(a: int, c: float) {.cdecl.} = discard
   var b: proc(a: int, c: float) {.noSideEffect.} = a
@@ -71,7 +71,4 @@ block: # Indrection through pragmas
   var fn2: proc(a: int): int {.inl2, p2.}
   fn2 = fn1
   fn1 = fn2
-block: # Lock levels differ
-  var fn1: proc(a: int){.locks: 3.}
-  var fn2: proc(a: int){.locks: 1.}
-  fn2 = fn1
+
diff --git a/tests/errmsgs/tsigmatch.nim b/tests/errmsgs/tsigmatch.nim
index 49b355982..85ed34169 100644
--- a/tests/errmsgs/tsigmatch.nim
+++ b/tests/errmsgs/tsigmatch.nim
@@ -12,34 +12,34 @@ proc f(b: B)
   but expression 'A()' is of type: A
 
 expression: f(A(), "extra")
-tsigmatch.nim(125, 6) Error: type mismatch: got <(string, proc (){.gcsafe, locks: 0.})>
+tsigmatch.nim(125, 6) Error: type mismatch: got <(string, proc (){.gcsafe.})>
 but expected one of:
 proc foo(x: (string, proc ()))
   first type mismatch at position: 1
   required type for x: (string, proc (){.closure.})
-  but expression '("foobar", proc () = echo(["Hello!"]))' is of type: (string, proc (){.gcsafe, locks: 0.})
+  but expression '("foobar", proc () = echo(["Hello!"]))' is of type: (string, proc (){.gcsafe.})
 
 expression: foo(("foobar", proc () = echo(["Hello!"])))
-tsigmatch.nim(132, 11) Error: type mismatch: got <proc (s: string): string{.noSideEffect, gcsafe, locks: 0.}>
+tsigmatch.nim(132, 11) Error: type mismatch: got <proc (s: string): string{.noSideEffect, gcsafe.}>
 but expected one of:
 proc foo[T, S](op: proc (x: T): S {.cdecl.}): auto
   first type mismatch at position: 1
   required type for op: proc (x: T): S{.cdecl.}
-  but expression 'fun' is of type: proc (s: string): string{.noSideEffect, gcsafe, locks: 0.}
+  but expression 'fun' is of type: proc (s: string): string{.noSideEffect, gcsafe.}
 proc foo[T, S](op: proc (x: T): S {.safecall.}): auto
   first type mismatch at position: 1
   required type for op: proc (x: T): S{.safecall.}
-  but expression 'fun' is of type: proc (s: string): string{.noSideEffect, gcsafe, locks: 0.}
+  but expression 'fun' is of type: proc (s: string): string{.noSideEffect, gcsafe.}
 
 expression: foo(fun)
-tsigmatch.nim(143, 13) Error: type mismatch: got <array[0..0, proc (x: int){.gcsafe, locks: 0.}]>
+tsigmatch.nim(143, 13) Error: type mismatch: got <array[0..0, proc (x: int){.gcsafe.}]>
 but expected one of:
-proc takesFuncs(fs: openArray[proc (x: int) {.gcsafe, locks: 0.}])
+proc takesFuncs(fs: openArray[proc (x: int) {.gcsafe.}])
   first type mismatch at position: 1
-  required type for fs: openArray[proc (x: int){.closure, gcsafe, locks: 0.}]
-  but expression '[proc (x: int) {.gcsafe, locks: 0.} = echo [x]]' is of type: array[0..0, proc (x: int){.gcsafe, locks: 0.}]
+  required type for fs: openArray[proc (x: int){.closure, gcsafe.}]
+  but expression '[proc (x: int) {.gcsafe.} = echo [x]]' is of type: array[0..0, proc (x: int){.gcsafe.}]
 
-expression: takesFuncs([proc (x: int) {.gcsafe, locks: 0.} = echo [x]])
+expression: takesFuncs([proc (x: int) {.gcsafe.} = echo [x]])
 tsigmatch.nim(149, 4) Error: type mismatch: got <int literal(10), a0: int literal(5), string>
 but expected one of:
 proc f(a0: uint8; b: string)
@@ -135,12 +135,12 @@ block:
   # bug #10285 Function signature don't match when inside seq/array/openArray
   # Note: the error message now shows `closure` which helps debugging the issue
   # out why it doesn't match
-  proc takesFunc(f: proc (x: int) {.gcsafe, locks: 0.}) =
+  proc takesFunc(f: proc (x: int) {.gcsafe.}) =
     echo "takes single Func"
-  proc takesFuncs(fs: openArray[proc (x: int) {.gcsafe, locks: 0.}]) =
+  proc takesFuncs(fs: openArray[proc (x: int) {.gcsafe.}]) =
     echo "takes multiple Func"
-  takesFunc(proc (x: int) {.gcsafe, locks: 0.} = echo x)         # works
-  takesFuncs([proc (x: int) {.gcsafe, locks: 0.} = echo x])      # fails
+  takesFunc(proc (x: int) {.gcsafe.} = echo x)         # works
+  takesFuncs([proc (x: int) {.gcsafe.} = echo x])      # fails
 
 block:
   # bug https://github.com/nim-lang/Nim/issues/11061#issuecomment-508970465
diff --git a/tests/errmsgs/ttypeAllowed.nim b/tests/errmsgs/ttypeAllowed.nim
index 516b616e0..fdb4c70b8 100644
--- a/tests/errmsgs/ttypeAllowed.nim
+++ b/tests/errmsgs/ttypeAllowed.nim
@@ -2,10 +2,10 @@ discard """
 cmd: "nim check $file"
 errormsg: ""
 nimout: '''
-ttypeAllowed.nim(13, 5) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe, locks: 0.}' for let
-ttypeAllowed.nim(17, 7) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe, locks: 0.}' for const
-ttypeAllowed.nim(21, 5) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe, locks: 0.}' for var
-ttypeAllowed.nim(26, 10) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe, locks: 0.}' for result
+ttypeAllowed.nim(13, 5) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe.}' for let
+ttypeAllowed.nim(17, 7) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe.}' for const
+ttypeAllowed.nim(21, 5) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe.}' for var
+ttypeAllowed.nim(26, 10) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe.}' for result
 '''
 """
 
diff --git a/tests/generics/tprevent_double_bind.nim b/tests/generics/tprevent_double_bind.nim
index 86e080ab6..d8fc6e5d3 100644
--- a/tests/generics/tprevent_double_bind.nim
+++ b/tests/generics/tprevent_double_bind.nim
@@ -1,5 +1,5 @@
 discard """
-  errormsg: "type mismatch: got <TT[seq[string]], proc (v: int){.gcsafe, locks: 0.}>"
+  errormsg: "type mismatch: got <TT[seq[string]], proc (v: int){.gcsafe.}>"
   line: 20
 """
 
diff --git a/tests/lent/t16898.nim b/tests/lent/t16898.nim
index ea7c934ef..a69c6d244 100644
--- a/tests/lent/t16898.nim
+++ b/tests/lent/t16898.nim
@@ -1,5 +1,5 @@
 discard """
-  errormsg: "invalid type: 'lent QuadraticExt' in this context: 'proc (r: var QuadraticExt, a: lent QuadraticExt, b: lent QuadraticExt){.noSideEffect, gcsafe, locks: 0.}' for proc"
+  errormsg: "invalid type: 'lent QuadraticExt' in this context: 'proc (r: var QuadraticExt, a: lent QuadraticExt, b: lent QuadraticExt){.noSideEffect, gcsafe.}' for proc"
 """
 
 # bug #16898
diff --git a/tests/overload/tproc_types_dont_like_subtypes.nim b/tests/overload/tproc_types_dont_like_subtypes.nim
index d322f41be..6774be156 100644
--- a/tests/overload/tproc_types_dont_like_subtypes.nim
+++ b/tests/overload/tproc_types_dont_like_subtypes.nim
@@ -1,5 +1,5 @@
 discard """
-  errormsg: "got <B, proc (b: B){.closure, gcsafe, locks: 0.}>"
+  errormsg: "got <B, proc (b: B){.closure, gcsafe.}>"
   line: 20
 """
 
diff --git a/tests/pragmas/tlocks.nim b/tests/pragmas/tlocks.nim
index 6c2a9f9e9..5d6fcdd9c 100644
--- a/tests/pragmas/tlocks.nim
+++ b/tests/pragmas/tlocks.nim
@@ -1,7 +1,3 @@
-discard """
-  matrix: "--mm:arc; --mm:refc"
-"""
-
 type SomeBase* = ref object of RootObj
 type SomeDerived* = ref object of SomeBase
   memberProc*: proc ()
diff --git a/tests/statictypes/t9255.nim b/tests/statictypes/t9255.nim
index 99ca2a23c..aec2fbaf5 100644
--- a/tests/statictypes/t9255.nim
+++ b/tests/statictypes/t9255.nim
@@ -1,6 +1,6 @@
 discard """
   errormsg: '''
-type mismatch: got <proc (a0: int): string{.noSideEffect, gcsafe, locks: 0.}>
+type mismatch: got <proc (a0: int): string{.noSideEffect, gcsafe.}>
 '''
   line: 13
 """
diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim
index 4f396c735..f6159d942 100644
--- a/tests/stdlib/ttimes.nim
+++ b/tests/stdlib/ttimes.nim
@@ -11,12 +11,12 @@ when not defined(js):
 proc staticTz(hours, minutes, seconds: int = 0): Timezone {.noSideEffect.} =
   let offset = hours * 3600 + minutes * 60 + seconds
 
-  proc zonedTimeFromAdjTime(adjTime: Time): ZonedTime {.locks: 0.} =
+  proc zonedTimeFromAdjTime(adjTime: Time): ZonedTime =
     result.isDst = false
     result.utcOffset = offset
     result.time = adjTime + initDuration(seconds = offset)
 
-  proc zonedTimeFromTime(time: Time): ZonedTime {.locks: 0.}=
+  proc zonedTimeFromTime(time: Time): ZonedTime =
     result.isDst = false
     result.utcOffset = offset
     result.time = time
diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim
index 25ec2cc12..ad1dfc3df 100644
--- a/tests/vm/tvmmisc.nim
+++ b/tests/vm/tvmmisc.nim
@@ -361,7 +361,7 @@ block: # bug #14340
     envelopeSin[a]()
 
   block:
-    type Mutator = proc() {.noSideEffect, gcsafe, locks: 0.}
+    type Mutator = proc() {.noSideEffect, gcsafe.}
     proc mutator0() = discard
     const mTable = [Mutator(mutator0)]
     var i=0