fixes another effect inference bug [backport:1.6] (#19100)
* fixes another effect inference bug [backport:1.6]
This commit is contained in:
parent
f2f15e9726
commit
fce89cb60a
7 changed files with 85 additions and 11 deletions
|
|
@ -851,6 +851,9 @@ proc trackCall(tracked: PEffects; n: PNode) =
|
||||||
elif isIndirectCall(tracked, a):
|
elif isIndirectCall(tracked, a):
|
||||||
assumeTheWorst(tracked, n, op)
|
assumeTheWorst(tracked, n, op)
|
||||||
gcsafeAndSideeffectCheck()
|
gcsafeAndSideeffectCheck()
|
||||||
|
else:
|
||||||
|
if strictEffects in tracked.c.features and a.kind == nkSym and a.sym.kind in routineKinds:
|
||||||
|
propagateEffects(tracked, n, a.sym)
|
||||||
else:
|
else:
|
||||||
mergeRaises(tracked, effectList[exceptionEffects], n)
|
mergeRaises(tracked, effectList[exceptionEffects], n)
|
||||||
mergeTags(tracked, effectList[tagEffects], n)
|
mergeTags(tracked, effectList[tagEffects], n)
|
||||||
|
|
|
||||||
|
|
@ -733,7 +733,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
|
|
||||||
proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn},
|
proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn},
|
||||||
inheritable = defined(nimInheritHandles)):
|
inheritable = defined(nimInheritHandles)):
|
||||||
owned(Future[tuple[address: string, client: AsyncFD]]) =
|
owned(Future[tuple[address: string, client: AsyncFD]]) {.gcsafe.} =
|
||||||
## Accepts a new connection. Returns a future containing the client socket
|
## Accepts a new connection. Returns a future containing the client socket
|
||||||
## corresponding to that connection and the remote address of the client.
|
## corresponding to that connection and the remote address of the client.
|
||||||
## The future will complete when the connection is successfully accepted.
|
## The future will complete when the connection is successfully accepted.
|
||||||
|
|
@ -800,7 +800,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
|
|
||||||
var ol = newCustom()
|
var ol = newCustom()
|
||||||
ol.data = CompletionData(fd: socket, cb:
|
ol.data = CompletionData(fd: socket, cb:
|
||||||
proc (fd: AsyncFD, bytesCount: DWORD, errcode: OSErrorCode) =
|
proc (fd: AsyncFD, bytesCount: DWORD, errcode: OSErrorCode) {.gcsafe.} =
|
||||||
if not retFuture.finished:
|
if not retFuture.finished:
|
||||||
if errcode == OSErrorCode(-1):
|
if errcode == OSErrorCode(-1):
|
||||||
completeAccept()
|
completeAccept()
|
||||||
|
|
|
||||||
|
|
@ -437,7 +437,7 @@ macro `%*`*(x: untyped): untyped =
|
||||||
## `%` for every element.
|
## `%` for every element.
|
||||||
result = toJsonImpl(x)
|
result = toJsonImpl(x)
|
||||||
|
|
||||||
proc `==`*(a, b: JsonNode): bool =
|
proc `==`*(a, b: JsonNode): bool {.noSideEffect.} =
|
||||||
## Check two nodes for equality
|
## Check two nodes for equality
|
||||||
if a.isNil:
|
if a.isNil:
|
||||||
if b.isNil: return true
|
if b.isNil: return true
|
||||||
|
|
@ -464,12 +464,16 @@ proc `==`*(a, b: JsonNode): bool =
|
||||||
if a.fields.len != b.fields.len: return false
|
if a.fields.len != b.fields.len: return false
|
||||||
for key, val in a.fields:
|
for key, val in a.fields:
|
||||||
if not b.fields.hasKey(key): return false
|
if not b.fields.hasKey(key): return false
|
||||||
|
when defined(nimHasEffectsOf):
|
||||||
|
{.noSideEffect.}:
|
||||||
|
if b.fields[key] != val: return false
|
||||||
|
else:
|
||||||
if b.fields[key] != val: return false
|
if b.fields[key] != val: return false
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc hash*(n: OrderedTable[string, JsonNode]): Hash {.noSideEffect.}
|
proc hash*(n: OrderedTable[string, JsonNode]): Hash {.noSideEffect.}
|
||||||
|
|
||||||
proc hash*(n: JsonNode): Hash =
|
proc hash*(n: JsonNode): Hash {.noSideEffect.} =
|
||||||
## Compute the hash for a JSON node
|
## Compute the hash for a JSON node
|
||||||
case n.kind
|
case n.kind
|
||||||
of JArray:
|
of JArray:
|
||||||
|
|
|
||||||
|
|
@ -354,7 +354,7 @@ var onUnhandledException*: (proc (errorMsg: string) {.
|
||||||
## The default is to write a stacktrace to `stderr` and then call `quit(1)`.
|
## The default is to write a stacktrace to `stderr` and then call `quit(1)`.
|
||||||
## Unstable API.
|
## Unstable API.
|
||||||
|
|
||||||
proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
|
proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy, gcsafe.} =
|
||||||
when hasSomeStackTrace:
|
when hasSomeStackTrace:
|
||||||
var buf = newStringOfCap(2000)
|
var buf = newStringOfCap(2000)
|
||||||
if e.trace.len == 0:
|
if e.trace.len == 0:
|
||||||
|
|
@ -362,6 +362,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
|
||||||
else:
|
else:
|
||||||
var trace = $e.trace
|
var trace = $e.trace
|
||||||
add(buf, trace)
|
add(buf, trace)
|
||||||
|
{.gcsafe.}:
|
||||||
`=destroy`(trace)
|
`=destroy`(trace)
|
||||||
add(buf, "Error: unhandled exception: ")
|
add(buf, "Error: unhandled exception: ")
|
||||||
add(buf, e.msg)
|
add(buf, e.msg)
|
||||||
|
|
@ -373,6 +374,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
|
||||||
onUnhandledException(buf)
|
onUnhandledException(buf)
|
||||||
else:
|
else:
|
||||||
showErrorMessage2(buf)
|
showErrorMessage2(buf)
|
||||||
|
{.gcsafe.}:
|
||||||
`=destroy`(buf)
|
`=destroy`(buf)
|
||||||
else:
|
else:
|
||||||
# ugly, but avoids heap allocations :-)
|
# ugly, but avoids heap allocations :-)
|
||||||
|
|
@ -387,6 +389,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
|
||||||
if e.trace.len != 0:
|
if e.trace.len != 0:
|
||||||
var trace = $e.trace
|
var trace = $e.trace
|
||||||
add(buf, trace)
|
add(buf, trace)
|
||||||
|
{.gcsafe.}:
|
||||||
`=destroy`(trace)
|
`=destroy`(trace)
|
||||||
add(buf, "Error: unhandled exception: ")
|
add(buf, "Error: unhandled exception: ")
|
||||||
add(buf, e.msg)
|
add(buf, e.msg)
|
||||||
|
|
@ -398,7 +401,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
|
||||||
else:
|
else:
|
||||||
showErrorMessage(buf.addr, L)
|
showErrorMessage(buf.addr, L)
|
||||||
|
|
||||||
proc reportUnhandledError(e: ref Exception) {.nodestroy.} =
|
proc reportUnhandledError(e: ref Exception) {.nodestroy, gcsafe.} =
|
||||||
if unhandledExceptionHook != nil:
|
if unhandledExceptionHook != nil:
|
||||||
unhandledExceptionHook(e)
|
unhandledExceptionHook(e)
|
||||||
when hostOS != "any":
|
when hostOS != "any":
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): poin
|
||||||
q.cap = newCap
|
q.cap = newCap
|
||||||
result = q
|
result = q
|
||||||
|
|
||||||
proc shrink*[T](x: var seq[T]; newLen: Natural) =
|
proc shrink*[T](x: var seq[T]; newLen: Natural) {.tags: [].} =
|
||||||
when nimvm:
|
when nimvm:
|
||||||
setLen(x, newLen)
|
setLen(x, newLen)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
63
tests/effects/tnestedprocs.nim
Normal file
63
tests/effects/tnestedprocs.nim
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
discard """
|
||||||
|
cmd: "nim check --hints:off $file"
|
||||||
|
nimout: '''tnestedprocs.nim(27, 8) Error: 'inner' can have side effects
|
||||||
|
> tnestedprocs.nim(29, 13) Hint: 'inner' calls `.sideEffect` 'outer2'
|
||||||
|
>> tnestedprocs.nim(26, 6) Hint: 'outer2' called by 'inner'
|
||||||
|
|
||||||
|
tnestedprocs.nim(45, 8) Error: 'inner' can have side effects
|
||||||
|
> tnestedprocs.nim(47, 13) Hint: 'inner' calls `.sideEffect` 'outer6'
|
||||||
|
>> tnestedprocs.nim(44, 6) Hint: 'outer6' called by 'inner'
|
||||||
|
|
||||||
|
tnestedprocs.nim(58, 41) Error: type mismatch: got <proc ()> but expected 'proc (){.closure, noSideEffect.}'
|
||||||
|
Pragma mismatch: got '{..}', but expected '{.noSideEffect.}'.
|
||||||
|
'''
|
||||||
|
errormsg: "type mismatch: got <proc ()> but expected 'proc (){.closure, noSideEffect.}'"
|
||||||
|
"""
|
||||||
|
{.experimental: "strictEffects".}
|
||||||
|
proc outer {.noSideEffect.} =
|
||||||
|
proc inner(p: int) =
|
||||||
|
if p == 0:
|
||||||
|
outer()
|
||||||
|
|
||||||
|
inner(4)
|
||||||
|
|
||||||
|
outer()
|
||||||
|
|
||||||
|
proc outer2 =
|
||||||
|
proc inner(p: int) {.noSideEffect.} =
|
||||||
|
if p == 0:
|
||||||
|
outer2()
|
||||||
|
|
||||||
|
inner(4)
|
||||||
|
|
||||||
|
outer2()
|
||||||
|
|
||||||
|
proc outer3(p: int) {.noSideEffect.} =
|
||||||
|
proc inner(p: int) {.noSideEffect.} =
|
||||||
|
if p == 0:
|
||||||
|
p.outer3()
|
||||||
|
|
||||||
|
inner(4)
|
||||||
|
|
||||||
|
outer3(5)
|
||||||
|
|
||||||
|
proc outer6 =
|
||||||
|
proc inner(p: int) {.noSideEffect.} =
|
||||||
|
if p == 0:
|
||||||
|
outer6()
|
||||||
|
|
||||||
|
inner(4)
|
||||||
|
echo "bad"
|
||||||
|
|
||||||
|
outer6()
|
||||||
|
|
||||||
|
|
||||||
|
proc outer4 =
|
||||||
|
proc inner(p: int) {.noSideEffect.} =
|
||||||
|
if p == 0:
|
||||||
|
let x: proc () {.noSideEffect.} = outer4
|
||||||
|
x()
|
||||||
|
|
||||||
|
inner(4)
|
||||||
|
|
||||||
|
outer4()
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
output: '''34'''
|
output: '''34'''
|
||||||
|
joinable: false
|
||||||
"""
|
"""
|
||||||
|
|
||||||
{.compile("cfunction.c", "-DNUMBER_HERE=34").}
|
{.compile("cfunction.c", "-DNUMBER_HERE=34").}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue