Merge branch 'devel' into araq-pipeline

This commit is contained in:
Andreas Rumpf
2022-10-11 14:29:36 +02:00
committed by GitHub
61 changed files with 135 additions and 377 deletions

View File

@@ -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.

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:
@@ -905,7 +905,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)

View File

@@ -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

View File

@@ -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",

View File

@@ -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:

View File

@@ -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)

View File

@@ -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:

View File

@@ -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):

View File

@@ -1595,10 +1595,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
c.inheritancePenalty = 0
let x = typeRel(c, branch, aOrig, flags)
maxInheritance = max(maxInheritance, c.inheritancePenalty)
# 'or' implies maximum matching result:
if x > result: result = x
if result >= isSubtype:
if result >= isIntConv:
if result > isGeneric: result = isGeneric
bindingRet result
else:

View File

@@ -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:

View File

@@ -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
=======================================

View File

@@ -375,7 +375,7 @@ Ast Pattern Matching is a macro library to aid in writing complex
macros. This can be seen as a good example of how to repurpose the
Nim syntax tree with new semantics.
[Ast Pattern Matching](https://github.com/krux02/ast-pattern-matching)
[Ast Pattern Matching](https://github.com/nim-lang/ast-pattern-matching)
OpenGL Sandbox
--------------

View File

@@ -142,7 +142,7 @@ proc csource(args: string) =
proc bundleC2nim(args: string) =
cloneDependency(distDir, "https://github.com/nim-lang/c2nim.git")
nimCompile("dist/c2nim/c2nim",
options = "--noNimblePath --useVersion:1.6 --path:. " & args)
options = "--noNimblePath --path:. " & args)
proc bundleNimbleExe(latest: bool, args: string) =
let commit = if latest: "HEAD" else: NimbleStableCommit
@@ -150,7 +150,7 @@ proc bundleNimbleExe(latest: bool, args: string) =
commit = commit, allowBundled = true)
# installer.ini expects it under $nim/bin
nimCompile("dist/nimble/src/nimble.nim",
options = "-d:release --mm:refc --useVersion:1.6 --noNimblePath " & args)
options = "-d:release --mm:refc --noNimblePath " & args)
proc bundleNimsuggest(args: string) =
nimCompileFold("Compile nimsuggest", "nimsuggest/nimsuggest.nim",

View File

@@ -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.

View File

@@ -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.

View File

@@ -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)

View File

@@ -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:

View File

@@ -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[]))

View File

@@ -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.}

View File

@@ -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.
##

View File

@@ -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())

View File

@@ -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

View File

@@ -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.

View File

@@ -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,

View File

@@ -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 =

View File

@@ -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

View File

@@ -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

View File

@@ -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
"""

View File

@@ -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
"""

View File

@@ -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

View File

@@ -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
"""

View File

@@ -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
"""

View File

@@ -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
"""

View File

@@ -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
"""

View File

@@ -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],

View File

@@ -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
"""

View File

@@ -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
"""

View File

@@ -33,7 +33,7 @@ py
py
px
6
proc (){.closure, gcsafe, locks: 0.}
proc (){.closure, gcsafe.}
'''
"""

View File

@@ -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
]#

View File

@@ -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
"""

View File

@@ -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
"""

View File

@@ -1,5 +1,5 @@
discard """
errormsg: '''type mismatch: got <proc (s: string){.locks: 0.}>'''
errormsg: '''type mismatch: got <proc (s: string)>'''
line: 11
"""
#5620

View File

@@ -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
"""

View File

@@ -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
"""

View File

@@ -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.}
'''
"""

View File

@@ -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.}'.
'''
"""

View File

@@ -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
"""

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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
'''
"""

10
tests/generics/t7446.nim Normal file
View File

@@ -0,0 +1,10 @@
proc foo(x: Natural or SomeUnsignedInt):int =
when x is int:
result = 1
else:
result = 2
let a = 10
doAssert foo(a) == 1
let b = 10'u8
doAssert foo(b) == 2

View File

@@ -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
"""

View File

@@ -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

View File

@@ -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
"""

View File

@@ -1,7 +1,3 @@
discard """
matrix: "--mm:arc; --mm:refc"
"""
type SomeBase* = ref object of RootObj
type SomeDerived* = ref object of SomeBase
memberProc*: proc ()

View File

@@ -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
"""

View File

@@ -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

View File

@@ -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